Commit ad7c314b2483817989bed5e6aa9da79c3bc35c76

Authored by YevhenBondarenko
Committed by Andrew Shvayka
1 parent bc21db00

TbResource extends SearchTextBased, created TbResourceInfo

Showing 34 changed files with 764 additions and 340 deletions
... ... @@ -39,6 +39,8 @@ import org.thingsboard.server.common.data.EntityView;
39 39 import org.thingsboard.server.common.data.EntityViewInfo;
40 40 import org.thingsboard.server.common.data.HasName;
41 41 import org.thingsboard.server.common.data.HasTenantId;
  42 +import org.thingsboard.server.common.data.TbResourceInfo;
  43 +import org.thingsboard.server.common.data.TbResource;
42 44 import org.thingsboard.server.common.data.Tenant;
43 45 import org.thingsboard.server.common.data.TenantInfo;
44 46 import org.thingsboard.server.common.data.TenantProfile;
... ... @@ -59,6 +61,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
59 61 import org.thingsboard.server.common.data.id.EntityId;
60 62 import org.thingsboard.server.common.data.id.EntityIdFactory;
61 63 import org.thingsboard.server.common.data.id.EntityViewId;
  64 +import org.thingsboard.server.common.data.id.TbResourceId;
62 65 import org.thingsboard.server.common.data.id.RuleChainId;
63 66 import org.thingsboard.server.common.data.id.RuleNodeId;
64 67 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -77,7 +80,6 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
77 80 import org.thingsboard.server.common.data.plugin.ComponentType;
78 81 import org.thingsboard.server.common.data.rule.RuleChain;
79 82 import org.thingsboard.server.common.data.rule.RuleNode;
80   -import org.thingsboard.server.common.data.widget.WidgetType;
81 83 import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
82 84 import org.thingsboard.server.common.data.widget.WidgetsBundle;
83 85 import org.thingsboard.server.common.msg.TbMsg;
... ... @@ -99,6 +101,7 @@ import org.thingsboard.server.dao.model.ModelConstants;
99 101 import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
100 102 import org.thingsboard.server.dao.oauth2.OAuth2Service;
101 103 import org.thingsboard.server.dao.relation.RelationService;
  104 +import org.thingsboard.server.dao.resource.TbResourceService;
102 105 import org.thingsboard.server.dao.rule.RuleChainService;
103 106 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
104 107 import org.thingsboard.server.dao.tenant.TenantProfileService;
... ... @@ -227,6 +230,9 @@ public abstract class BaseController {
227 230 protected PartitionService partitionService;
228 231
229 232 @Autowired
  233 + protected TbResourceService resourceService;
  234 +
  235 + @Autowired
230 236 protected TbQueueProducerProvider producerProvider;
231 237
232 238 @Autowired
... ... @@ -461,6 +467,9 @@ public abstract class BaseController {
461 467 case WIDGET_TYPE:
462 468 checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation);
463 469 return;
  470 + case TB_RESOURCE:
  471 + checkResourceId(new TbResourceId(entityId.getId()), operation);
  472 + return;
464 473 default:
465 474 throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
466 475 }
... ... @@ -668,6 +677,30 @@ public abstract class BaseController {
668 677 return ruleNode;
669 678 }
670 679
  680 + TbResource checkResourceId(TbResourceId resourceId, Operation operation) throws ThingsboardException {
  681 + try {
  682 + validateId(resourceId, "Incorrect resourceId " + resourceId);
  683 + TbResource resource = resourceService.findResourceById(getCurrentUser().getTenantId(), resourceId);
  684 + checkNotNull(resource);
  685 + accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resource);
  686 + return resource;
  687 + } catch (Exception e) {
  688 + throw handleException(e, false);
  689 + }
  690 + }
  691 +
  692 + TbResourceInfo checkResourceInfoId(TbResourceId resourceId, Operation operation) throws ThingsboardException {
  693 + try {
  694 + validateId(resourceId, "Incorrect resourceId " + resourceId);
  695 + TbResourceInfo resourceInfo = resourceService.findResourceInfoById(getCurrentUser().getTenantId(), resourceId);
  696 + checkNotNull(resourceInfo);
  697 + accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resourceInfo);
  698 + return resourceInfo;
  699 + } catch (Exception e) {
  700 + throw handleException(e, false);
  701 + }
  702 + }
  703 +
671 704 @SuppressWarnings("unchecked")
672 705 protected <I extends EntityId> I emptyId(EntityType entityType) {
673 706 return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
... ... @@ -884,8 +917,8 @@ public abstract class BaseController {
884 917
885 918 protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException {
886 919 String dashboardId = additionalInfo.has(requiredFields) ? additionalInfo.get(requiredFields).asText() : null;
887   - if(dashboardId != null && !dashboardId.equals("null")) {
888   - if(dashboardService.findDashboardById(getTenantId(), new DashboardId(UUID.fromString(dashboardId))) == null) {
  920 + if (dashboardId != null && !dashboardId.equals("null")) {
  921 + if (dashboardService.findDashboardById(getTenantId(), new DashboardId(UUID.fromString(dashboardId))) == null) {
889 922 additionalInfo.remove(requiredFields);
890 923 }
891 924 }
... ...
application/src/main/java/org/thingsboard/server/controller/TbResourceController.java renamed from application/src/main/java/org/thingsboard/server/controller/ResourceController.java
... ... @@ -18,20 +18,23 @@ package org.thingsboard.server.controller;
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.springframework.security.access.prepost.PreAuthorize;
20 20 import org.springframework.web.bind.annotation.PathVariable;
  21 +import org.springframework.web.bind.annotation.RequestBody;
21 22 import org.springframework.web.bind.annotation.RequestMapping;
22 23 import org.springframework.web.bind.annotation.RequestMethod;
23 24 import org.springframework.web.bind.annotation.RequestParam;
24 25 import org.springframework.web.bind.annotation.ResponseBody;
25 26 import org.springframework.web.bind.annotation.RestController;
26   -import org.thingsboard.server.common.data.Resource;
27   -import org.thingsboard.server.common.data.ResourceType;
  27 +import org.thingsboard.server.common.data.TbResource;
  28 +import org.thingsboard.server.common.data.TbResourceInfo;
28 29 import org.thingsboard.server.common.data.exception.ThingsboardException;
29   -import org.thingsboard.server.common.data.id.TenantId;
  30 +import org.thingsboard.server.common.data.id.TbResourceId;
30 31 import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
31 32 import org.thingsboard.server.common.data.page.PageData;
32 33 import org.thingsboard.server.common.data.page.PageLink;
33   -import org.thingsboard.server.dao.resource.ResourceService;
  34 +import org.thingsboard.server.dao.resource.TbResourceService;
34 35 import org.thingsboard.server.queue.util.TbCoreComponent;
  36 +import org.thingsboard.server.service.security.permission.Operation;
  37 +import org.thingsboard.server.service.security.permission.Resource;
35 38
36 39 import java.util.List;
37 40
... ... @@ -39,21 +42,50 @@ import java.util.List;
39 42 @RestController
40 43 @TbCoreComponent
41 44 @RequestMapping("/api")
42   -public class ResourceController extends BaseController {
  45 +public class TbResourceController extends BaseController {
43 46
44   - private final ResourceService resourceService;
  47 + public static final String RESOURCE_ID = "resourceId";
45 48
46   - public ResourceController(ResourceService resourceService) {
  49 + private final TbResourceService resourceService;
  50 +
  51 + public TbResourceController(TbResourceService resourceService) {
47 52 this.resourceService = resourceService;
48 53 }
49 54
50 55 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  56 + @RequestMapping(value = "/resource/info/{resourceId}", method = RequestMethod.GET)
  57 + @ResponseBody
  58 + public TbResourceInfo getResourceInfoById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
  59 + checkParameter(RESOURCE_ID, strResourceId);
  60 + try {
  61 + TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
  62 + return checkResourceInfoId(resourceId, Operation.READ);
  63 + } catch (Exception e) {
  64 + throw handleException(e);
  65 + }
  66 + }
  67 +
  68 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  69 + @RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.GET)
  70 + @ResponseBody
  71 + public TbResource getResourceById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
  72 + checkParameter(RESOURCE_ID, strResourceId);
  73 + try {
  74 + TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
  75 + return checkResourceId(resourceId, Operation.READ);
  76 + } catch (Exception e) {
  77 + throw handleException(e);
  78 + }
  79 + }
  80 +
  81 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
51 82 @RequestMapping(value = "/resource", method = RequestMethod.POST)
52 83 @ResponseBody
53   - public Resource saveResource(Resource resource) throws ThingsboardException {
  84 + public TbResource saveResource(@RequestBody TbResource resource) throws ThingsboardException {
54 85 try {
55 86 resource.setTenantId(getTenantId());
56   - Resource savedResource = checkNotNull(resourceService.saveResource(resource));
  87 + checkEntity(resource.getId(), resource, Resource.TB_RESOURCE);
  88 + TbResource savedResource = checkNotNull(resourceService.saveResource(resource));
57 89 tbClusterService.onResourceChange(savedResource, null);
58 90 return savedResource;
59 91 } catch (Exception e) {
... ... @@ -64,15 +96,14 @@ public class ResourceController extends BaseController {
64 96 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
65 97 @RequestMapping(value = "/resource", method = RequestMethod.GET)
66 98 @ResponseBody
67   - public PageData<Resource> getResources(@RequestParam(required = false) boolean system,
68   - @RequestParam int pageSize,
69   - @RequestParam int page,
70   - @RequestParam(required = false) String textSearch,
71   - @RequestParam(required = false) String sortProperty,
72   - @RequestParam(required = false) String sortOrder) throws ThingsboardException {
  99 + public PageData<TbResourceInfo> getResources(@RequestParam int pageSize,
  100 + @RequestParam int page,
  101 + @RequestParam(required = false) String textSearch,
  102 + @RequestParam(required = false) String sortProperty,
  103 + @RequestParam(required = false) String sortOrder) throws ThingsboardException {
73 104 try {
74 105 PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
75   - return checkNotNull(resourceService.findResourcesByTenantId(system ? TenantId.SYS_TENANT_ID : getTenantId(), pageLink));
  106 + return checkNotNull(resourceService.findResourcesByTenantId(getTenantId(), pageLink));
76 107 } catch (Exception e) {
77 108 throw handleException(e);
78 109 }
... ... @@ -82,10 +113,10 @@ public class ResourceController extends BaseController {
82 113 @RequestMapping(value = "/resource/lwm2m/page", method = RequestMethod.GET)
83 114 @ResponseBody
84 115 public List<LwM2mObject> getLwm2mListObjectsPage(@RequestParam int pageSize,
85   - @RequestParam int page,
86   - @RequestParam(required = false) String textSearch,
87   - @RequestParam(required = false) String sortProperty,
88   - @RequestParam(required = false) String sortOrder) throws ThingsboardException {
  116 + @RequestParam int page,
  117 + @RequestParam(required = false) String textSearch,
  118 + @RequestParam(required = false) String sortProperty,
  119 + @RequestParam(required = false) String sortOrder) throws ThingsboardException {
89 120 try {
90 121 PageLink pageLink = new PageLink(pageSize, page, textSearch);
91 122 return checkNotNull(resourceService.findLwM2mObjectPage(getTenantId(), sortProperty, sortOrder, pageLink));
... ... @@ -95,7 +126,7 @@ public class ResourceController extends BaseController {
95 126 }
96 127
97 128 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
98   - @RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET)
  129 + @RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET)
99 130 @ResponseBody
100 131 public List<LwM2mObject> getLwm2mListObjects(@RequestParam String sortOrder,
101 132 @RequestParam String sortProperty,
... ... @@ -108,14 +139,15 @@ public class ResourceController extends BaseController {
108 139 }
109 140
110 141 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
111   - @RequestMapping(value = "/resource/{resourceType}/{resourceId}", method = RequestMethod.DELETE)
  142 + @RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.DELETE)
112 143 @ResponseBody
113   - public void deleteResource(@PathVariable("resourceType") ResourceType resourceType,
114   - @PathVariable("resourceId") String resourceId) throws ThingsboardException {
  144 + public void deleteResource(@PathVariable("resourceId") String strResourceId) throws ThingsboardException {
  145 + checkParameter("resourceId", strResourceId);
115 146 try {
116   - Resource resource = checkNotNull(resourceService.getResource(getTenantId(), resourceType, resourceId));
117   - resourceService.deleteResource(getTenantId(), resourceType, resourceId);
118   - tbClusterService.onResourceDeleted(resource, null);
  147 + TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
  148 + TbResource tbResource = checkResourceId(resourceId, Operation.DELETE);
  149 + resourceService.deleteResource(getTenantId(), resourceId);
  150 + tbClusterService.onResourceDeleted(tbResource, null);
119 151 } catch (Exception e) {
120 152 throw handleException(e);
121 153 }
... ...
... ... @@ -22,8 +22,8 @@ import org.springframework.beans.factory.annotation.Value;
22 22 import org.springframework.stereotype.Component;
23 23 import org.springframework.util.StringUtils;
24 24 import org.thingsboard.server.common.data.Dashboard;
25   -import org.thingsboard.server.common.data.Resource;
26 25 import org.thingsboard.server.common.data.ResourceType;
  26 +import org.thingsboard.server.common.data.TbResource;
27 27 import org.thingsboard.server.common.data.id.CustomerId;
28 28 import org.thingsboard.server.common.data.id.EntityId;
29 29 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
35 35 import org.thingsboard.server.dao.dashboard.DashboardService;
36 36 import org.thingsboard.server.dao.exception.DataValidationException;
37 37 import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
38   -import org.thingsboard.server.dao.resource.ResourceService;
  38 +import org.thingsboard.server.dao.resource.TbResourceService;
39 39 import org.thingsboard.server.dao.rule.RuleChainService;
40 40 import org.thingsboard.server.dao.widget.WidgetTypeService;
41 41 import org.thingsboard.server.dao.widget.WidgetsBundleService;
... ... @@ -95,7 +95,7 @@ public class InstallScripts {
95 95 private OAuth2ConfigTemplateService oAuth2TemplateService;
96 96
97 97 @Autowired
98   - private ResourceService resourceService;
  98 + private TbResourceService resourceService;
99 99
100 100 public Path getTenantRuleChainsDir() {
101 101 return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
... ... @@ -204,13 +204,10 @@ public class InstallScripts {
204 204 path -> {
205 205 try {
206 206 byte[] fileBytes = Files.readAllBytes(path);
207   - String source = new String(fileBytes);
208   - Resource resource = new Resource();
  207 + TbResource resource = new TbResource();
209 208 resource.setTenantId(TenantId.SYS_TENANT_ID);
210 209 resource.setResourceType(ResourceType.LWM2M_MODEL);
211   - resource.setResourceId(getValueByTag(source, "ObjectID") + "_" + getValueByTag(source, "ObjectVersion"));
212   - resource.setTextSearch(resource.getResourceId() + ":" + getValueByTag(source, "Name"));
213   - resource.setValue(Base64.getEncoder().encodeToString(fileBytes));
  210 + resource.setData(Base64.getEncoder().encodeToString(fileBytes));
214 211 resourceService.saveResource(resource);
215 212 } catch (Exception e) {
216 213 throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", path.toString()));
... ... @@ -219,28 +216,6 @@ public class InstallScripts {
219 216 );
220 217 }
221 218 }
222   -
223   - Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks");
224   - try {
225   - Resource resource = new Resource();
226   - resource.setTenantId(TenantId.SYS_TENANT_ID);
227   - resource.setResourceType(ResourceType.JKS);
228   - resource.setResourceId(jksPath.getFileName().toString());
229   - resource.setTextSearch(jksPath.getFileName().toString());
230   - resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
231   - resourceService.saveResource(resource);
232   - } catch (Exception e) {
233   - log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
234   - throw new RuntimeException("Unable to load lwm2m serverKeyStore", e);
235   - }
236   - }
237   -
238   - private String getValueByTag(String source, String tag) {
239   - int lenTag = ("<" + tag + ">").length();
240   - int indStart = source.indexOf("<" + tag + ">");
241   - int indEnd = source.indexOf("</" + tag + ">");
242   - return (indStart > 0 && indEnd > 0) ? source.substring(indStart + lenTag, indEnd) : null;
243   -
244 219 }
245 220
246 221 public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {
... ...
... ... @@ -450,14 +450,17 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
450 450 try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
451 451 log.info("Updating schema ...");
452 452 try {
453   - conn.createStatement().execute("CREATE TABLE IF NOT EXISTS resource (" +
454   - " tenant_id uuid NOT NULL," +
455   - " resource_type varchar(32) NOT NULL," +
456   - " resource_id varchar(255) NOT NULL," +
457   - " text_search varchar(255)," +
458   - " resource_value varchar," +
459   - " CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)" +
460   - " );");
  453 + conn.createStatement().execute("CREATE TABLE IF NOT EXISTS resource ( " +
  454 + "id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY, " +
  455 + "created_time bigint NOT NULL, " +
  456 + "tenant_id uuid NOT NULL, " +
  457 + "title varchar(255) NOT NULL, " +
  458 + "resource_type varchar(32) NOT NULL, " +
  459 + "resource_key varchar(255) NOT NULL, " +
  460 + "search_text varchar(255), " +
  461 + "data varchar, " +
  462 + "CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)" +
  463 + ");");
461 464
462 465 conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;");
463 466 installScripts.loadSystemLwm2mResources();
... ...
... ... @@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.Device;
26 26 import org.thingsboard.server.common.data.DeviceProfile;
27 27 import org.thingsboard.server.common.data.EntityType;
28 28 import org.thingsboard.server.common.data.HasName;
29   -import org.thingsboard.server.common.data.Resource;
  29 +import org.thingsboard.server.common.data.TbResource;
30 30 import org.thingsboard.server.common.data.Tenant;
31 31 import org.thingsboard.server.common.data.TenantProfile;
32 32 import org.thingsboard.server.common.data.id.DeviceId;
... ... @@ -249,28 +249,27 @@ public class DefaultTbClusterService implements TbClusterService {
249 249 }
250 250
251 251 @Override
252   - public void onResourceChange(Resource resource, TbQueueCallback callback) {
  252 + public void onResourceChange(TbResource resource, TbQueueCallback callback) {
253 253 TenantId tenantId = resource.getTenantId();
254   - log.trace("[{}][{}][{}] Processing change resource", tenantId, resource.getResourceType(), resource.getResourceId());
  254 + log.trace("[{}][{}][{}] Processing change resource", tenantId, resource.getResourceType(), resource.getResourceKey());
255 255 TransportProtos.ResourceUpdateMsg resourceUpdateMsg = TransportProtos.ResourceUpdateMsg.newBuilder()
256 256 .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
257 257 .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
258 258 .setResourceType(resource.getResourceType().name())
259   - .setResourceId(resource.getResourceId())
  259 + .setResourceKey(resource.getResourceKey())
260 260 .build();
261 261 ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setResourceUpdateMsg(resourceUpdateMsg).build();
262 262 broadcast(transportMsg, callback);
263 263 }
264 264
265 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());
  266 + public void onResourceDeleted(TbResource resource, TbQueueCallback callback) {
  267 + log.trace("[{}] Processing delete resource", resource);
269 268 TransportProtos.ResourceDeleteMsg resourceUpdateMsg = TransportProtos.ResourceDeleteMsg.newBuilder()
270   - .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
271   - .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
  269 + .setTenantIdMSB(resource.getTenantId().getId().getMostSignificantBits())
  270 + .setTenantIdLSB(resource.getTenantId().getId().getLeastSignificantBits())
272 271 .setResourceType(resource.getResourceType().name())
273   - .setResourceId(resource.getResourceId())
  272 + .setResourceKey(resource.getResourceKey())
274 273 .build();
275 274 ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setResourceDeleteMsg(resourceUpdateMsg).build();
276 275 broadcast(transportMsg, callback);
... ...
... ... @@ -19,7 +19,7 @@ import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
19 19 import org.thingsboard.server.common.data.ApiUsageState;
20 20 import org.thingsboard.server.common.data.Device;
21 21 import org.thingsboard.server.common.data.DeviceProfile;
22   -import org.thingsboard.server.common.data.Resource;
  22 +import org.thingsboard.server.common.data.TbResource;
23 23 import org.thingsboard.server.common.data.Tenant;
24 24 import org.thingsboard.server.common.data.TenantProfile;
25 25 import org.thingsboard.server.common.data.id.EntityId;
... ... @@ -73,7 +73,7 @@ public interface TbClusterService {
73 73
74 74 void onDeviceDeleted(Device device, TbQueueCallback callback);
75 75
76   - void onResourceChange(Resource resource, TbQueueCallback callback);
  76 + void onResourceChange(TbResource resource, TbQueueCallback callback);
77 77
78   - void onResourceDeleted(Resource resource, TbQueueCallback callback);
  78 + void onResourceDeleted(TbResource resource, TbQueueCallback callback);
79 79 }
... ...
... ... @@ -36,7 +36,8 @@ public enum Resource {
36 36 OAUTH2_CONFIGURATION_TEMPLATE(),
37 37 TENANT_PROFILE(EntityType.TENANT_PROFILE),
38 38 DEVICE_PROFILE(EntityType.DEVICE_PROFILE),
39   - API_USAGE_STATE(EntityType.API_USAGE_STATE);
  39 + API_USAGE_STATE(EntityType.API_USAGE_STATE),
  40 + TB_RESOURCE(EntityType.TB_RESOURCE);
40 41
41 42 private final EntityType entityType;
42 43
... ...
... ... @@ -38,6 +38,7 @@ public class SysAdminPermissions extends AbstractPermissions {
38 38 put(Resource.OAUTH2_CONFIGURATION_INFO, PermissionChecker.allowAllPermissionChecker);
39 39 put(Resource.OAUTH2_CONFIGURATION_TEMPLATE, PermissionChecker.allowAllPermissionChecker);
40 40 put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker);
  41 + put(Resource.TB_RESOURCE, systemEntityPermissionChecker);
41 42 }
42 43
43 44 private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() {
... ...
... ... @@ -41,6 +41,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
41 41 put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
42 42 put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker);
43 43 put(Resource.API_USAGE_STATE, tenantEntityPermissionChecker);
  44 + put(Resource.TB_RESOURCE, tbResourcePermissionChecker);
44 45 }
45 46
46 47 public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() {
... ... @@ -101,4 +102,19 @@ public class TenantAdminPermissions extends AbstractPermissions {
101 102 }
102 103
103 104 };
  105 +
  106 + private static final PermissionChecker tbResourcePermissionChecker = new PermissionChecker() {
  107 +
  108 + @Override
  109 + public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) {
  110 + if (entity.getTenantId() == null || entity.getTenantId().isNullUid()) {
  111 + return operation == Operation.READ;
  112 + }
  113 + if (!user.getTenantId().equals(entity.getTenantId())) {
  114 + return false;
  115 + }
  116 + return true;
  117 + }
  118 +
  119 + };
104 120 }
... ...
... ... @@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.DataConstants;
31 31 import org.thingsboard.server.common.data.Device;
32 32 import org.thingsboard.server.common.data.DeviceProfile;
33 33 import org.thingsboard.server.common.data.EntityType;
34   -import org.thingsboard.server.common.data.Resource;
  34 +import org.thingsboard.server.common.data.TbResource;
35 35 import org.thingsboard.server.common.data.ResourceType;
36 36 import org.thingsboard.server.common.data.TenantProfile;
37 37 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
... ... @@ -56,7 +56,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
56 56 import org.thingsboard.server.dao.device.provision.ProvisionRequest;
57 57 import org.thingsboard.server.dao.device.provision.ProvisionResponse;
58 58 import org.thingsboard.server.dao.relation.RelationService;
59   -import org.thingsboard.server.dao.resource.ResourceService;
  59 +import org.thingsboard.server.dao.resource.TbResourceService;
60 60 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
61 61 import org.thingsboard.server.gen.transport.TransportProtos;
62 62 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
... ... @@ -108,7 +108,7 @@ public class DefaultTransportApiService implements TransportApiService {
108 108 private final TbClusterService tbClusterService;
109 109 private final DataDecodingEncodingService dataDecodingEncodingService;
110 110 private final DeviceProvisionService deviceProvisionService;
111   - private final ResourceService resourceService;
  111 + private final TbResourceService resourceService;
112 112
113 113 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
114 114
... ... @@ -117,7 +117,7 @@ public class DefaultTransportApiService implements TransportApiService {
117 117 RelationService relationService, DeviceCredentialsService deviceCredentialsService,
118 118 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
119 119 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
120   - DeviceProvisionService deviceProvisionService, ResourceService resourceService) {
  120 + DeviceProvisionService deviceProvisionService, TbResourceService resourceService) {
121 121 this.deviceProfileCache = deviceProfileCache;
122 122 this.tenantProfileCache = tenantProfileCache;
123 123 this.apiUsageStateService = apiUsageStateService;
... ... @@ -365,12 +365,12 @@ public class DefaultTransportApiService implements TransportApiService {
365 365 private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) {
366 366 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
367 367 ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType());
368   - String resourceId = requestMsg.getResourceId();
  368 + String resourceKey = requestMsg.getResourceKey();
369 369 TransportProtos.GetResourceResponseMsg.Builder builder = TransportProtos.GetResourceResponseMsg.newBuilder();
370   - Resource resource = resourceService.getResource(tenantId, resourceType, resourceId);
  370 + TbResource resource = resourceService.getResource(tenantId, resourceType, resourceKey);
371 371
372 372 if (resource == null && !tenantId.equals(TenantId.SYS_TENANT_ID)) {
373   - resource = resourceService.getResource(TenantId.SYS_TENANT_ID, resourceType, resourceId);
  373 + resource = resourceService.getResource(TenantId.SYS_TENANT_ID, resourceType, resourceKey);
374 374 }
375 375
376 376 if (resource != null) {
... ...
common/dao-api/src/main/java/org/thingsboard/server/dao/resource/TbResourceService.java renamed from common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java
... ... @@ -15,24 +15,30 @@
15 15 */
16 16 package org.thingsboard.server.dao.resource;
17 17
18   -import org.thingsboard.server.common.data.Resource;
  18 +import org.eclipse.leshan.core.model.InvalidDDFFileException;
  19 +import org.thingsboard.server.common.data.TbResource;
  20 +import org.thingsboard.server.common.data.TbResourceInfo;
19 21 import org.thingsboard.server.common.data.ResourceType;
  22 +import org.thingsboard.server.common.data.id.TbResourceId;
20 23 import org.thingsboard.server.common.data.id.TenantId;
21 24 import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
22 25 import org.thingsboard.server.common.data.page.PageData;
23 26 import org.thingsboard.server.common.data.page.PageLink;
24 27
  28 +import java.io.IOException;
25 29 import java.util.List;
26 30
27 31
28   -public interface ResourceService {
29   - Resource saveResource(Resource resource);
  32 +public interface TbResourceService {
  33 + TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException;
30 34
31   - Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  35 + TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
32 36
33   - PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
  37 + TbResource findResourceById(TenantId tenantId, TbResourceId resourceId);
34 38
35   - List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType);
  39 + TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId);
  40 +
  41 + PageData<TbResourceInfo> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
36 42
37 43 List<LwM2mObject> findLwM2mObject(TenantId tenantId,
38 44 String sortOrder,
... ... @@ -44,7 +50,7 @@ public interface ResourceService {
44 50 String sortOrder,
45 51 PageLink pageLink);
46 52
47   - void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  53 + void deleteResource(TenantId tenantId, TbResourceId resourceId);
48 54
49 55 void deleteResourcesByTenantId(TenantId tenantId);
50 56 }
... ...
... ... @@ -19,5 +19,5 @@ package org.thingsboard.server.common.data;
19 19 * @author Andrew Shvayka
20 20 */
21 21 public enum EntityType {
22   - TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE;
  22 + TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE, TB_RESOURCE;
23 23 }
... ...
common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java renamed from common/data/src/main/java/org/thingsboard/server/common/data/Resource.java
... ... @@ -16,31 +16,54 @@
16 16 package org.thingsboard.server.common.data;
17 17
18 18 import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
19 20 import lombok.extern.slf4j.Slf4j;
20   -import org.thingsboard.server.common.data.id.TenantId;
21   -
22   -import java.io.Serializable;
  21 +import org.thingsboard.server.common.data.id.TbResourceId;
23 22
24 23 @Slf4j
25 24 @Data
26   -public class Resource implements HasTenantId, Serializable {
  25 +@EqualsAndHashCode(callSuper = true)
  26 +public class TbResource extends TbResourceInfo {
27 27
28 28 private static final long serialVersionUID = 7379609705527272306L;
29 29
30   - private TenantId tenantId;
31   - private ResourceType resourceType;
32   - private String resourceId;
33   - private String textSearch;
34   - private String value;
  30 + private String data;
  31 +
  32 + public TbResource() {
  33 + super();
  34 + }
  35 +
  36 + public TbResource(TbResourceId id) {
  37 + super(id);
  38 + }
  39 +
  40 + public TbResource(TbResourceInfo resourceInfo) {
  41 + super(resourceInfo);
  42 + }
  43 +
  44 + public TbResource(TbResource resource) {
  45 + super(resource);
  46 + this.data = resource.getData();
  47 + }
35 48
36 49 @Override
37 50 public String toString() {
38   - final StringBuilder res = new StringBuilder("Resource{");
39   - res.append("tenantId=").append(tenantId);
40   - res.append(", resourceType='").append(resourceType).append('\'');
41   - res.append(", resourceId='").append(resourceId).append('\'');
42   - res.append(", textSearch='").append(textSearch).append('\'');
43   - res.append('}');
44   - return res.toString();
  51 + StringBuilder builder = new StringBuilder();
  52 + builder.append("Resource [tenantId=");
  53 + builder.append(getTenantId());
  54 + builder.append(", id=");
  55 + builder.append(getUuidId());
  56 + builder.append(", createdTime=");
  57 + builder.append(createdTime);
  58 + builder.append(", title=");
  59 + builder.append(getTitle());
  60 + builder.append(", resourceType=");
  61 + builder.append(getResourceType());
  62 + builder.append(", resourceKey=");
  63 + builder.append(getResourceKey());
  64 + builder.append(", data=");
  65 + builder.append(data);
  66 + builder.append("]");
  67 + return builder.toString();
45 68 }
46 69 }
... ...
  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;
  17 +
  18 +import lombok.Data;
  19 +import lombok.EqualsAndHashCode;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.thingsboard.server.common.data.id.TbResourceId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
  23 +
  24 +@Slf4j
  25 +@Data
  26 +@EqualsAndHashCode(callSuper = true)
  27 +public class TbResourceInfo extends SearchTextBased<TbResourceId> implements HasTenantId {
  28 +
  29 + private TenantId tenantId;
  30 + private String title;
  31 + private ResourceType resourceType;
  32 + private String resourceKey;
  33 + private String searchText;
  34 +
  35 + public TbResourceInfo() {
  36 + super();
  37 + }
  38 +
  39 + public TbResourceInfo(TbResourceId id) {
  40 + super(id);
  41 + }
  42 +
  43 + public TbResourceInfo(TbResourceInfo resourceInfo) {
  44 + super(resourceInfo);
  45 + this.tenantId = resourceInfo.getTenantId();
  46 + this.title = resourceInfo.getTitle();
  47 + this.resourceType = resourceInfo.getResourceType();
  48 + this.resourceKey = resourceInfo.resourceKey;
  49 + }
  50 +
  51 + @Override
  52 + public String getSearchText() {
  53 + return searchText;
  54 + }
  55 +
  56 + @Override
  57 + public String toString() {
  58 + StringBuilder builder = new StringBuilder();
  59 + builder.append("ResourceInfo [tenantId=");
  60 + builder.append(tenantId);
  61 + builder.append(", id=");
  62 + builder.append(getUuidId());
  63 + builder.append(", createdTime=");
  64 + builder.append(createdTime);
  65 + builder.append(", title=");
  66 + builder.append(title);
  67 + builder.append(", resourceType=");
  68 + builder.append(resourceType);
  69 + builder.append(", resourceKey=");
  70 + builder.append(resourceKey);
  71 + builder.append("]");
  72 + return builder.toString();
  73 + }
  74 +}
... ...
... ... @@ -68,6 +68,8 @@ public class EntityIdFactory {
68 68 return new TenantProfileId(uuid);
69 69 case API_USAGE_STATE:
70 70 return new ApiUsageStateId(uuid);
  71 + case TB_RESOURCE:
  72 + return new TbResourceId(uuid);
71 73 }
72 74 throw new IllegalArgumentException("EntityType " + type + " is not supported!");
73 75 }
... ...
  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.id;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonCreator;
  19 +import com.fasterxml.jackson.annotation.JsonIgnore;
  20 +import com.fasterxml.jackson.annotation.JsonProperty;
  21 +import org.thingsboard.server.common.data.EntityType;
  22 +
  23 +import java.util.UUID;
  24 +
  25 +public class TbResourceId extends UUIDBased implements EntityId {
  26 +
  27 + private static final long serialVersionUID = 1L;
  28 +
  29 + @JsonCreator
  30 + public TbResourceId(@JsonProperty("id") UUID id) {
  31 + super(id);
  32 + }
  33 +
  34 + @JsonIgnore
  35 + @Override
  36 + public EntityType getEntityType() {
  37 + return EntityType.TB_RESOURCE;
  38 + }
  39 +}
... ...
... ... @@ -205,7 +205,7 @@ message GetResourceRequestMsg {
205 205 int64 tenantIdMSB = 1;
206 206 int64 tenantIdLSB = 2;
207 207 string resourceType = 3;
208   - string resourceId = 4;
  208 + string resourceKey = 4;
209 209 }
210 210
211 211 message GetResourceResponseMsg {
... ... @@ -257,14 +257,14 @@ message ResourceUpdateMsg {
257 257 int64 tenantIdMSB = 1;
258 258 int64 tenantIdLSB = 2;
259 259 string resourceType = 3;
260   - string resourceId = 4;
  260 + string resourceKey = 4;
261 261 }
262 262
263 263 message ResourceDeleteMsg {
264 264 int64 tenantIdMSB = 1;
265 265 int64 tenantIdLSB = 2;
266 266 string resourceType = 3;
267   - string resourceId = 4;
  267 + string resourceKey = 4;
268 268 }
269 269
270 270 message SessionCloseNotificationProto {
... ...
... ... @@ -124,7 +124,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
124 124 this.tenantId,
125 125 LWM2M_MODEL,
126 126 key).
127   - getValue();
  127 + getData();
128 128 return xmlB64 != null && !xmlB64.isEmpty() ?
129 129 lwM2mTransportContextServer.parseFromXmlToObjectModel(
130 130 Base64.getDecoder().decode(xmlB64),
... ...
... ... @@ -15,13 +15,13 @@
15 15 */
16 16 package org.thingsboard.server.common.transport;
17 17
18   -import org.thingsboard.server.common.data.Resource;
  18 +import org.thingsboard.server.common.data.TbResource;
19 19 import org.thingsboard.server.common.data.ResourceType;
20 20 import org.thingsboard.server.common.data.id.TenantId;
21 21
22 22 public interface TransportResourceCache {
23 23
24   - Resource get(TenantId tenantId, ResourceType resourceType, String resourceId);
  24 + TbResource get(TenantId tenantId, ResourceType resourceType, String resourceId);
25 25
26 26 void update(TenantId tenantId, ResourceType resourceType, String resourceI);
27 27
... ...
... ... @@ -19,7 +19,7 @@ import lombok.Data;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.springframework.context.annotation.Lazy;
21 21 import org.springframework.stereotype.Component;
22   -import org.thingsboard.server.common.data.Resource;
  22 +import org.thingsboard.server.common.data.TbResource;
23 23 import org.thingsboard.server.common.data.ResourceType;
24 24 import org.thingsboard.server.common.data.id.TenantId;
25 25 import org.thingsboard.server.common.transport.TransportResourceCache;
... ... @@ -42,8 +42,8 @@ import java.util.concurrent.locks.ReentrantLock;
42 42 public class DefaultTransportResourceCache implements TransportResourceCache {
43 43
44 44 private final Lock resourceFetchLock = new ReentrantLock();
45   - private final ConcurrentMap<ResourceKey, Resource> resources = new ConcurrentHashMap<>();
46   - private final Set<ResourceKey> keys = ConcurrentHashMap.newKeySet();
  45 + private final ConcurrentMap<ResourceCompositeKey, TbResource> resources = new ConcurrentHashMap<>();
  46 + private final Set<ResourceCompositeKey> keys = ConcurrentHashMap.newKeySet();
47 47 private final DataDecodingEncodingService dataDecodingEncodingService;
48 48 private final TransportService transportService;
49 49
... ... @@ -53,26 +53,26 @@ public class DefaultTransportResourceCache implements TransportResourceCache {
53 53 }
54 54
55 55 @Override
56   - public Resource get(TenantId tenantId, ResourceType resourceType, String resourceId) {
57   - ResourceKey resourceKey = new ResourceKey(tenantId, resourceType, resourceId);
58   - Resource resource;
  56 + public TbResource get(TenantId tenantId, ResourceType resourceType, String resourceKey) {
  57 + ResourceCompositeKey compositeKey = new ResourceCompositeKey(tenantId, resourceType, resourceKey);
  58 + TbResource resource;
59 59
60   - if (keys.contains(resourceKey)) {
61   - resource = resources.get(resourceKey);
  60 + if (keys.contains(compositeKey)) {
  61 + resource = resources.get(compositeKey);
62 62 if (resource == null) {
63   - resource = resources.get(resourceKey.getSystemKey());
  63 + resource = resources.get(compositeKey.getSystemKey());
64 64 }
65 65 } else {
66 66 resourceFetchLock.lock();
67 67 try {
68   - if (keys.contains(resourceKey)) {
69   - resource = resources.get(resourceKey);
  68 + if (keys.contains(compositeKey)) {
  69 + resource = resources.get(compositeKey);
70 70 if (resource == null) {
71   - resource = resources.get(resourceKey.getSystemKey());
  71 + resource = resources.get(compositeKey.getSystemKey());
72 72 }
73 73 } else {
74   - resource = fetchResource(resourceKey);
75   - keys.add(resourceKey);
  74 + resource = fetchResource(compositeKey);
  75 + keys.add(compositeKey);
76 76 }
77 77 } finally {
78 78 resourceFetchLock.unlock();
... ... @@ -82,20 +82,20 @@ public class DefaultTransportResourceCache implements TransportResourceCache {
82 82 return resource;
83 83 }
84 84
85   - private Resource fetchResource(ResourceKey resourceKey) {
86   - UUID tenantId = resourceKey.getTenantId().getId();
  85 + private TbResource fetchResource(ResourceCompositeKey compositeKey) {
  86 + UUID tenantId = compositeKey.getTenantId().getId();
87 87 TransportProtos.GetResourceRequestMsg.Builder builder = TransportProtos.GetResourceRequestMsg.newBuilder();
88 88 builder
89 89 .setTenantIdLSB(tenantId.getLeastSignificantBits())
90 90 .setTenantIdMSB(tenantId.getMostSignificantBits())
91   - .setResourceType(resourceKey.resourceType.name())
92   - .setResourceId(resourceKey.resourceId);
  91 + .setResourceType(compositeKey.resourceType.name())
  92 + .setResourceKey(compositeKey.resourceKey);
93 93 TransportProtos.GetResourceResponseMsg responseMsg = transportService.getResource(builder.build());
94 94
95   - Optional<Resource> optionalResource = dataDecodingEncodingService.decode(responseMsg.getResource().toByteArray());
  95 + Optional<TbResource> optionalResource = dataDecodingEncodingService.decode(responseMsg.getResource().toByteArray());
96 96 if (optionalResource.isPresent()) {
97   - Resource resource = optionalResource.get();
98   - resources.put(new ResourceKey(resource.getTenantId(), resource.getResourceType(), resource.getResourceId()), resource);
  97 + TbResource resource = optionalResource.get();
  98 + resources.put(new ResourceCompositeKey(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey()), resource);
99 99 return resource;
100 100 }
101 101
... ... @@ -103,28 +103,28 @@ public class DefaultTransportResourceCache implements TransportResourceCache {
103 103 }
104 104
105 105 @Override
106   - public void update(TenantId tenantId, ResourceType resourceType, String resourceId) {
107   - ResourceKey resourceKey = new ResourceKey(tenantId, resourceType, resourceId);
108   - if (keys.contains(resourceKey) || resources.containsKey(resourceKey)) {
109   - fetchResource(resourceKey);
  106 + public void update(TenantId tenantId, ResourceType resourceType, String resourceKey) {
  107 + ResourceCompositeKey compositeKey = new ResourceCompositeKey(tenantId, resourceType, resourceKey);
  108 + if (keys.contains(compositeKey) || resources.containsKey(compositeKey)) {
  109 + fetchResource(compositeKey);
110 110 }
111 111 }
112 112
113 113 @Override
114   - public void evict(TenantId tenantId, ResourceType resourceType, String resourceId) {
115   - ResourceKey resourceKey = new ResourceKey(tenantId, resourceType, resourceId);
116   - keys.remove(resourceKey);
117   - resources.remove(resourceKey);
  114 + public void evict(TenantId tenantId, ResourceType resourceType, String resourceKey) {
  115 + ResourceCompositeKey compositeKey = new ResourceCompositeKey(tenantId, resourceType, resourceKey);
  116 + keys.remove(compositeKey);
  117 + resources.remove(compositeKey);
118 118 }
119 119
120 120 @Data
121   - private static class ResourceKey {
  121 + private static class ResourceCompositeKey {
122 122 private final TenantId tenantId;
123 123 private final ResourceType resourceType;
124   - private final String resourceId;
  124 + private final String resourceKey;
125 125
126   - public ResourceKey getSystemKey() {
127   - return new ResourceKey(TenantId.SYS_TENANT_ID, resourceType, resourceId);
  126 + public ResourceCompositeKey getSystemKey() {
  127 + return new ResourceCompositeKey(TenantId.SYS_TENANT_ID, resourceType, resourceKey);
128 128 }
129 129 }
130 130 }
... ...
... ... @@ -708,13 +708,13 @@ public class DefaultTransportService implements TransportService {
708 708 TransportProtos.ResourceUpdateMsg msg = toSessionMsg.getResourceUpdateMsg();
709 709 TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
710 710 ResourceType resourceType = ResourceType.valueOf(msg.getResourceType());
711   - String resourceId = msg.getResourceId();
  711 + String resourceId = msg.getResourceKey();
712 712 transportResourceCache.update(tenantId, resourceType, resourceId);
713 713 } else if (toSessionMsg.hasResourceDeleteMsg()) {
714 714 TransportProtos.ResourceDeleteMsg msg = toSessionMsg.getResourceDeleteMsg();
715 715 TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
716 716 ResourceType resourceType = ResourceType.valueOf(msg.getResourceType());
717   - String resourceId = msg.getResourceId();
  717 + String resourceId = msg.getResourceKey();
718 718 transportResourceCache.evict(tenantId, resourceType, resourceId);
719 719 } else {
720 720 //TODO: should we notify the device actor about missed session?
... ...
... ... @@ -462,9 +462,9 @@ public class ModelConstants {
462 462 public static final String RESOURCE_TABLE_NAME = "resource";
463 463 public static final String RESOURCE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
464 464 public static final String RESOURCE_TYPE_COLUMN = "resource_type";
465   - public static final String RESOURCE_ID_COLUMN = "resource_id";
466   - public static final String TEXT_SEARCH_COLUMN = "text_search";
467   - public static final String RESOURCE_VALUE_COLUMN = "resource_value";
  465 + public static final String RESOURCE_KEY_COLUMN = "resource_key";
  466 + public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY;
  467 + public static final String RESOURCE_DATA_COLUMN = "data";
468 468
469 469
470 470 /**
... ...
  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 lombok.EqualsAndHashCode;
  20 +import org.thingsboard.server.common.data.ResourceType;
  21 +import org.thingsboard.server.common.data.TbResource;
  22 +import org.thingsboard.server.common.data.id.TbResourceId;
  23 +import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.dao.model.BaseSqlEntity;
  25 +import org.thingsboard.server.dao.model.SearchTextEntity;
  26 +
  27 +import javax.persistence.Column;
  28 +import javax.persistence.Entity;
  29 +import javax.persistence.Table;
  30 +import java.util.UUID;
  31 +
  32 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DATA_COLUMN;
  33 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
  34 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
  35 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
  36 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TITLE_COLUMN;
  37 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN;
  38 +import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
  39 +
  40 +@Data
  41 +@EqualsAndHashCode(callSuper = true)
  42 +@Entity
  43 +@Table(name = RESOURCE_TABLE_NAME)
  44 +public class TbResourceEntity extends BaseSqlEntity<TbResource> implements SearchTextEntity<TbResource> {
  45 +
  46 + @Column(name = RESOURCE_TENANT_ID_COLUMN, columnDefinition = "uuid")
  47 + private UUID tenantId;
  48 +
  49 + @Column(name = RESOURCE_TITLE_COLUMN)
  50 + private String title;
  51 +
  52 + @Column(name = RESOURCE_TYPE_COLUMN)
  53 + private String resourceType;
  54 +
  55 + @Column(name = RESOURCE_KEY_COLUMN)
  56 + private String resourceKey;
  57 +
  58 + @Column(name = SEARCH_TEXT_PROPERTY)
  59 + private String searchText;
  60 +
  61 + @Column(name = RESOURCE_DATA_COLUMN)
  62 + private String data;
  63 +
  64 + public TbResourceEntity() {
  65 + }
  66 +
  67 + public TbResourceEntity(TbResource resource) {
  68 + this.setUuid(resource.getId().getId());
  69 + this.tenantId = resource.getTenantId().getId();
  70 + this.title = resource.getTitle();
  71 + this.resourceType = resource.getResourceType().name();
  72 + this.resourceKey = resource.getResourceKey();
  73 + this.searchText = resource.getSearchText();
  74 + this.data = resource.getData();
  75 + }
  76 +
  77 + @Override
  78 + public TbResource toData() {
  79 + TbResource resource = new TbResource();
  80 + resource.setId(new TbResourceId(id));
  81 + resource.setCreatedTime(createdTime);
  82 + resource.setTenantId(new TenantId(tenantId));
  83 + resource.setTitle(title);
  84 + resource.setResourceType(ResourceType.valueOf(resourceType));
  85 + resource.setResourceKey(resourceKey);
  86 + resource.setSearchText(searchText);
  87 + resource.setData(data);
  88 + return resource;
  89 + }
  90 +
  91 + @Override
  92 + public String getSearchTextSource() {
  93 + return title;
  94 + }
  95 +}
... ...
dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java renamed from dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceEntity.java
... ... @@ -16,68 +16,75 @@
16 16 package org.thingsboard.server.dao.model.sql;
17 17
18 18 import lombok.Data;
19   -import org.thingsboard.server.common.data.Resource;
  19 +import lombok.EqualsAndHashCode;
20 20 import org.thingsboard.server.common.data.ResourceType;
  21 +import org.thingsboard.server.common.data.TbResourceInfo;
  22 +import org.thingsboard.server.common.data.id.TbResourceId;
21 23 import org.thingsboard.server.common.data.id.TenantId;
22   -import org.thingsboard.server.dao.model.ToData;
  24 +import org.thingsboard.server.dao.model.BaseSqlEntity;
  25 +import org.thingsboard.server.dao.model.SearchTextEntity;
23 26
24 27 import javax.persistence.Column;
25 28 import javax.persistence.Entity;
26   -import javax.persistence.Id;
27   -import javax.persistence.IdClass;
28 29 import javax.persistence.Table;
29 30 import java.util.UUID;
30 31
31   -import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ID_COLUMN;
  32 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
32 33 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
33 34 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
  35 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TITLE_COLUMN;
34 36 import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN;
35   -import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_VALUE_COLUMN;
36   -import static org.thingsboard.server.dao.model.ModelConstants.TEXT_SEARCH_COLUMN;
  37 +import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
37 38
38 39 @Data
  40 +@EqualsAndHashCode(callSuper = true)
39 41 @Entity
40 42 @Table(name = RESOURCE_TABLE_NAME)
41   -@IdClass(ResourceCompositeKey.class)
42   -public class ResourceEntity implements ToData<Resource> {
  43 +public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implements SearchTextEntity<TbResourceInfo> {
43 44
44   - @Id
45 45 @Column(name = RESOURCE_TENANT_ID_COLUMN, columnDefinition = "uuid")
46 46 private UUID tenantId;
47 47
48   - @Id
  48 + @Column(name = RESOURCE_TITLE_COLUMN)
  49 + private String title;
  50 +
49 51 @Column(name = RESOURCE_TYPE_COLUMN)
50 52 private String resourceType;
51 53
52   - @Id
53   - @Column(name = RESOURCE_ID_COLUMN)
54   - private String resourceId;
55   -
56   - @Column(name = TEXT_SEARCH_COLUMN)
57   - private String textSearch;
  54 + @Column(name = RESOURCE_KEY_COLUMN)
  55 + private String resourceKey;
58 56
59   - @Column(name = RESOURCE_VALUE_COLUMN)
60   - private String value;
  57 + @Column(name = SEARCH_TEXT_PROPERTY)
  58 + private String searchText;
61 59
62   - public ResourceEntity() {
  60 + public TbResourceInfoEntity() {
63 61 }
64 62
65   - public ResourceEntity(Resource resource) {
  63 + public TbResourceInfoEntity(TbResourceInfo resource) {
  64 + this.setUuid(resource.getId().getId());
  65 + this.setCreatedTime(resource.getCreatedTime());
66 66 this.tenantId = resource.getTenantId().getId();
  67 + this.title = resource.getTitle();
67 68 this.resourceType = resource.getResourceType().name();
68   - this.resourceId = resource.getResourceId();
69   - this.textSearch = resource.getTextSearch();
70   - this.value = resource.getValue();
  69 + this.resourceKey = resource.getResourceKey();
  70 + this.searchText = resource.getSearchText();
71 71 }
72 72
73 73 @Override
74   - public Resource toData() {
75   - Resource resource = new Resource();
  74 + public TbResourceInfo toData() {
  75 + TbResourceInfo resource = new TbResourceInfo();
  76 + resource.setId(new TbResourceId(id));
  77 + resource.setCreatedTime(createdTime);
76 78 resource.setTenantId(new TenantId(tenantId));
  79 + resource.setTitle(title);
77 80 resource.setResourceType(ResourceType.valueOf(resourceType));
78   - resource.setResourceId(resourceId);
79   - resource.setTextSearch(textSearch);
80   - resource.setValue(value);
  81 + resource.setResourceKey(resourceKey);
  82 + resource.setSearchText(searchText);
81 83 return resource;
82 84 }
  85 +
  86 + @Override
  87 + public String getSearchTextSource() {
  88 + return title;
  89 + }
83 90 }
... ...
dao/src/main/java/org/thingsboard/server/dao/resource/BaseTbResourceService.java renamed from dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java
... ... @@ -21,8 +21,10 @@ import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
21 21 import org.eclipse.leshan.core.model.InvalidDDFFileException;
22 22 import org.eclipse.leshan.core.model.ObjectModel;
23 23 import org.springframework.stereotype.Service;
24   -import org.thingsboard.server.common.data.Resource;
25 24 import org.thingsboard.server.common.data.ResourceType;
  25 +import org.thingsboard.server.common.data.TbResource;
  26 +import org.thingsboard.server.common.data.TbResourceInfo;
  27 +import org.thingsboard.server.common.data.id.TbResourceId;
26 28 import org.thingsboard.server.common.data.id.TenantId;
27 29 import org.thingsboard.server.common.data.lwm2m.LwM2mInstance;
28 30 import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
... ... @@ -30,6 +32,8 @@ import org.thingsboard.server.common.data.lwm2m.LwM2mResource;
30 32 import org.thingsboard.server.common.data.page.PageData;
31 33 import org.thingsboard.server.common.data.page.PageLink;
32 34 import org.thingsboard.server.dao.exception.DataValidationException;
  35 +import org.thingsboard.server.dao.service.PaginatedRemover;
  36 +import org.thingsboard.server.dao.service.Validator;
33 37
34 38 import java.io.ByteArrayInputStream;
35 39 import java.io.IOException;
... ... @@ -44,61 +48,88 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
44 48
45 49 @Service
46 50 @Slf4j
47   -public class BaseResourceService implements ResourceService {
  51 +public class BaseTbResourceService implements TbResourceService {
48 52
49   - private final ResourceDao resourceDao;
  53 + public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId ";
  54 + private final TbResourceDao resourceDao;
  55 + private final TbResourceInfoDao resourceInfoDao;
  56 + private final DDFFileParser ddfFileParser;
50 57
51   - public BaseResourceService(ResourceDao resourceDao) {
  58 + public BaseTbResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao) {
52 59 this.resourceDao = resourceDao;
  60 + this.resourceInfoDao = resourceInfoDao;
  61 + this.ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
53 62 }
54 63
55 64 @Override
56   - public Resource saveResource(Resource resource) {
  65 + public TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException {
57 66 log.trace("Executing saveResource [{}]", resource);
  67 +
  68 + if (resource.getId() == null && ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) {
  69 + List<ObjectModel> objectModels =
  70 + ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
  71 + if (!objectModels.isEmpty()) {
  72 + ObjectModel objectModel = objectModels.get(0);
  73 +
  74 + String resourceKey = objectModel.id + "_" + objectModel.getVersion();
  75 + String name = objectModel.name;
  76 + resource.setResourceKey(resourceKey);
  77 + resource.setTitle(name);
  78 + resource.setSearchText(resourceKey + ":" + name);
  79 + }
  80 + }
  81 +
58 82 validate(resource);
  83 +
59 84 return resourceDao.saveResource(resource);
60 85 }
61 86
62 87 @Override
63   - public Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
64   - log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceId);
65   - validate(tenantId, resourceType, resourceId);
66   - return resourceDao.getResource(tenantId, resourceType, resourceId);
  88 + public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {
  89 + log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceKey);
  90 + validate(tenantId, resourceType, resourceKey);
  91 + return resourceDao.getResource(tenantId, resourceType, resourceKey);
67 92 }
68 93
69 94 @Override
70   - public void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
71   - log.trace("Executing deleteResource [{}] [{}] [{}]", tenantId, resourceType, resourceId);
72   - validate(tenantId, resourceType, resourceId);
73   - resourceDao.deleteResource(tenantId, resourceType, resourceId);
  95 + public TbResource findResourceById(TenantId tenantId, TbResourceId resourceId) {
  96 + log.trace("Executing findResourceById [{}] [{}]", tenantId, resourceId);
  97 + Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
  98 + return resourceDao.findById(tenantId, resourceId.getId());
74 99 }
75 100
76 101 @Override
77   - public PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
78   - log.trace("Executing findByTenantId [{}]", tenantId);
79   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
80   - return resourceDao.findAllByTenantId(tenantId, pageLink);
  102 + public TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId) {
  103 + log.trace("Executing findResourceInfoById [{}] [{}]", tenantId, resourceId);
  104 + Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
  105 + return resourceInfoDao.findById(tenantId, resourceId.getId());
81 106 }
82 107
  108 + @Override
  109 + public void deleteResource(TenantId tenantId, TbResourceId resourceId) {
  110 + log.trace("Executing deleteResource [{}] [{}]", tenantId, resourceId);
  111 + Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
  112 + resourceDao.removeById(tenantId, resourceId.getId());
  113 + }
83 114
84 115 @Override
85   - public List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType) {
  116 + public PageData<TbResourceInfo> findResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
86 117 log.trace("Executing findByTenantId [{}]", tenantId);
87 118 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
88   - return resourceDao.findAllByTenantIdAndResourceType(tenantId, resourceType);
  119 + return resourceInfoDao.findTbResourcesByTenantId(tenantId.getId(), pageLink);
89 120 }
90 121
91 122 @Override
92 123 public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) {
93 124 log.trace("Executing findByTenantId [{}]", tenantId);
94 125 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
95   - PageData<Resource> resourcePageData = resourceDao.findResourcesByTenantIdAndResourceType(
96   - tenantId,
97   - ResourceType.LWM2M_MODEL, pageLink);
98   - return resourcePageData.getData().stream()
99   - .map(this::toLwM2mObject)
100   - .sorted(getComparator(sortProperty, sortOrder))
101   - .collect(Collectors.toList());
  126 + PageData<TbResource> resourcePageData = resourceDao.findResourcesByTenantIdAndResourceType(
  127 + tenantId,
  128 + ResourceType.LWM2M_MODEL, pageLink);
  129 + return resourcePageData.getData().stream()
  130 + .map(this::toLwM2mObject)
  131 + .sorted(getComparator(sortProperty, sortOrder))
  132 + .collect(Collectors.toList());
102 133 }
103 134
104 135 @Override
... ... @@ -107,9 +138,9 @@ public class BaseResourceService implements ResourceService {
107 138 String[] objectIds) {
108 139 log.trace("Executing findByTenantId [{}]", tenantId);
109 140 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
110   - List<Resource> resources = resourceDao.findResourcesByTenantIdAndResourceType(tenantId, ResourceType.LWM2M_MODEL,
111   - objectIds,
112   - null);
  141 + List<TbResource> resources = resourceDao.findResourcesByTenantIdAndResourceType(tenantId, ResourceType.LWM2M_MODEL,
  142 + objectIds,
  143 + null);
113 144 return resources.stream()
114 145 .map(this::toLwM2mObject)
115 146 .sorted(getComparator(sortProperty, sortOrder))
... ... @@ -118,21 +149,21 @@ public class BaseResourceService implements ResourceService {
118 149
119 150 @Override
120 151 public void deleteResourcesByTenantId(TenantId tenantId) {
121   - log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId);
  152 + log.trace("Executing deleteResourcesByTenantId, tenantId [{}]", tenantId);
122 153 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
123   - resourceDao.removeAllByTenantId(tenantId);
  154 + tenantResourcesRemover.removeEntities(tenantId, tenantId);
124 155 }
125 156
126   - protected void validate(Resource resource) {
  157 + protected void validate(TbResource resource) {
127 158 if (resource == null) {
128 159 throw new DataValidationException("Resource should be specified!");
129 160 }
130   - if (resource.getValue() == null) {
  161 + if (resource.getData() == null) {
131 162 throw new DataValidationException("Resource value should be specified!");
132 163 }
133   - validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceId());
  164 + validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey());
134 165 if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && this.toLwM2mObject(resource) == null) {
135   - throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getTextSearch()));
  166 + throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
136 167 }
137 168 }
138 169
... ... @@ -146,18 +177,18 @@ public class BaseResourceService implements ResourceService {
146 177 validateId(tenantId, "Incorrect tenantId ");
147 178 }
148 179
149   - private LwM2mObject toLwM2mObject(Resource resource) {
  180 + private LwM2mObject toLwM2mObject(TbResource resource) {
150 181 try {
151 182 DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
152 183 List<ObjectModel> objectModels =
153   - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getValue())), resource.getTextSearch());
  184 + ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
154 185 if (objectModels.size() == 0) {
155 186 return null;
156 187 } else {
157 188 ObjectModel obj = objectModels.get(0);
158 189 LwM2mObject lwM2mObject = new LwM2mObject();
159 190 lwM2mObject.setId(obj.id);
160   - lwM2mObject.setKeyId(resource.getResourceId());
  191 + lwM2mObject.setKeyId(resource.getResourceKey());
161 192 lwM2mObject.setName(obj.name);
162 193 lwM2mObject.setMultiple(obj.multiple);
163 194 lwM2mObject.setMandatory(obj.mandatory);
... ... @@ -170,12 +201,12 @@ public class BaseResourceService implements ResourceService {
170 201 resources.add(lwM2mResource);
171 202 }
172 203 });
173   - instance.setResources(resources.stream().toArray(LwM2mResource[]::new));
  204 + instance.setResources(resources.toArray(LwM2mResource[]::new));
174 205 lwM2mObject.setInstances(new LwM2mInstance[]{instance});
175 206 return lwM2mObject;
176 207 }
177 208 } catch (IOException | InvalidDDFFileException e) {
178   - log.error("Could not parse the XML of objectModel with name [{}]", resource.getTextSearch(), e);
  209 + log.error("Could not parse the XML of objectModel with name [{}]", resource.getSearchText(), e);
179 210 return null;
180 211 }
181 212 }
... ... @@ -190,4 +221,17 @@ public class BaseResourceService implements ResourceService {
190 221 return "DESC".equals(sortOrder) ? comparator.reversed() : comparator;
191 222 }
192 223
  224 + private PaginatedRemover<TenantId, TbResource> tenantResourcesRemover =
  225 + new PaginatedRemover<>() {
  226 +
  227 + @Override
  228 + protected PageData<TbResource> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
  229 + return resourceDao.findAllByTenantId(id, pageLink);
  230 + }
  231 +
  232 + @Override
  233 + protected void removeEntity(TenantId tenantId, TbResource entity) {
  234 + deleteResource(tenantId, new TbResourceId(entity.getUuidId()));
  235 + }
  236 + };
193 237 }
... ...
dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java renamed from dao/src/main/java/org/thingsboard/server/dao/resource/ResourceDao.java
... ... @@ -15,33 +15,29 @@
15 15 */
16 16 package org.thingsboard.server.dao.resource;
17 17
18   -import org.thingsboard.server.common.data.Resource;
19 18 import org.thingsboard.server.common.data.ResourceType;
  19 +import org.thingsboard.server.common.data.TbResource;
20 20 import org.thingsboard.server.common.data.id.TenantId;
21 21 import org.thingsboard.server.common.data.page.PageData;
22 22 import org.thingsboard.server.common.data.page.PageLink;
  23 +import org.thingsboard.server.dao.Dao;
23 24
24 25 import java.util.List;
25 26
26   -public interface ResourceDao {
  27 +public interface TbResourceDao extends Dao<TbResource> {
27 28
28   - Resource saveResource(Resource resource);
  29 + TbResource saveResource(TbResource resource);
29 30
30   - Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  31 + TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
31 32
32   - void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  33 + PageData<TbResource> findAllByTenantId(TenantId tenantId, PageLink pageLink);
33 34
34   - PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink);
  35 + PageData<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
  36 + ResourceType resourceType,
  37 + PageLink pageLink);
35 38
36   - PageData<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
37   - ResourceType resourceType,
38   - PageLink pageLink);
39   -
40   - List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType);
41   -
42   - List<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
43   - ResourceType resourceType,
44   - String[] objectIds,
45   - String searchText);
46   - void removeAllByTenantId(TenantId tenantId);
  39 + List<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
  40 + ResourceType resourceType,
  41 + String[] objectIds,
  42 + String searchText);
47 43 }
... ...
dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java renamed from dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceCompositeKey.java
... ... @@ -13,32 +13,17 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.model.sql;
  16 +package org.thingsboard.server.dao.resource;
17 17
18   -import lombok.AllArgsConstructor;
19   -import lombok.Data;
20   -import lombok.NoArgsConstructor;
21   -import org.thingsboard.server.common.data.Resource;
  18 +import org.thingsboard.server.common.data.TbResourceInfo;
  19 +import org.thingsboard.server.common.data.page.PageData;
  20 +import org.thingsboard.server.common.data.page.PageLink;
  21 +import org.thingsboard.server.dao.Dao;
22 22
23   -import javax.persistence.Transient;
24   -import java.io.Serializable;
25 23 import java.util.UUID;
26 24
27   -@NoArgsConstructor
28   -@AllArgsConstructor
29   -@Data
30   -public class ResourceCompositeKey implements Serializable {
  25 +public interface TbResourceInfoDao extends Dao<TbResourceInfo> {
31 26
32   - @Transient
33   - private static final long serialVersionUID = -3789469030818742769L;
  27 + PageData<TbResourceInfo> findTbResourcesByTenantId(UUID tenantId, PageLink pageLink);
34 28
35   - private UUID tenantId;
36   - private String resourceType;
37   - private String resourceId;
38   -
39   - public ResourceCompositeKey(Resource resource) {
40   - this.tenantId = resource.getTenantId().getId();
41   - this.resourceType = resource.getResourceType().name();
42   - this.resourceId = resource.getResourceId();
43   - }
44 29 }
... ...
dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java renamed from dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceDaoImpl.java
... ... @@ -16,72 +16,64 @@
16 16 package org.thingsboard.server.dao.sql.resource;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.data.repository.CrudRepository;
19 20 import org.springframework.stereotype.Component;
20 21 import org.springframework.transaction.annotation.Transactional;
21   -import org.thingsboard.server.common.data.Resource;
22 22 import org.thingsboard.server.common.data.ResourceType;
  23 +import org.thingsboard.server.common.data.TbResource;
23 24 import org.thingsboard.server.common.data.id.TenantId;
24 25 import org.thingsboard.server.common.data.page.PageData;
25 26 import org.thingsboard.server.common.data.page.PageLink;
26 27 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;
  28 +import org.thingsboard.server.dao.model.sql.TbResourceEntity;
  29 +import org.thingsboard.server.dao.resource.TbResourceDao;
  30 +import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
30 31
31 32 import java.util.List;
32 33 import java.util.Objects;
  34 +import java.util.UUID;
33 35
34 36 @Slf4j
35 37 @Component
36   -public class ResourceDaoImpl implements ResourceDao {
  38 +public class JpaTbResourceDao extends JpaAbstractSearchTextDao<TbResourceEntity, TbResource> implements TbResourceDao {
37 39
38   - private final ResourceRepository resourceRepository;
  40 + private final TbResourceRepository resourceRepository;
39 41
40   - public ResourceDaoImpl(ResourceRepository resourceRepository) {
  42 + public JpaTbResourceDao(TbResourceRepository resourceRepository) {
41 43 this.resourceRepository = resourceRepository;
42 44 }
43 45
44 46 @Override
45   - @Transactional
46   - public Resource saveResource(Resource resource) {
47   - return DaoUtil.getData(resourceRepository.save(new ResourceEntity(resource)));
  47 + protected Class<TbResourceEntity> getEntityClass() {
  48 + return TbResourceEntity.class;
48 49 }
49 50
50 51 @Override
51   - public Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
52   - ResourceCompositeKey key = new ResourceCompositeKey();
53   - key.setTenantId(tenantId.getId());
54   - key.setResourceType(resourceType.name());
55   - key.setResourceId(resourceId);
56   -
57   - return DaoUtil.getData(resourceRepository.findById(key));
  52 + protected CrudRepository<TbResourceEntity, UUID> getCrudRepository() {
  53 + return resourceRepository;
58 54 }
59 55
60 56 @Override
61 57 @Transactional
62   - public void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
63   - ResourceCompositeKey key = new ResourceCompositeKey();
64   - key.setTenantId(tenantId.getId());
65   - key.setResourceType(resourceType.name());
66   - key.setResourceId(resourceId);
67   -
68   - resourceRepository.deleteById(key);
  58 + public TbResource saveResource(TbResource resource) {
  59 + return DaoUtil.getData(resourceRepository.save(new TbResourceEntity(resource)));
69 60 }
70 61
71 62 @Override
72   - public PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
73   - return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
  63 + public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {
  64 +
  65 + return DaoUtil.getData(resourceRepository.findByTenantIdAndResourceTypeAndResourceKey(tenantId.getId(), resourceType.name(), resourceKey));
74 66 }
75 67
76 68 @Override
77   - public List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType) {
78   - return DaoUtil.convertDataList(resourceRepository.findAllByTenantIdAndResourceType(tenantId.getId(), resourceType.name()));
  69 + public PageData<TbResource> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
  70 + return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
79 71 }
80 72
81 73 @Override
82   - public PageData<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
83   - ResourceType resourceType,
84   - PageLink pageLink) {
  74 + public PageData<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
  75 + ResourceType resourceType,
  76 + PageLink pageLink) {
85 77 return DaoUtil.toPageData(resourceRepository.findResourcesPage(
86 78 tenantId.getId(),
87 79 TenantId.SYS_TENANT_ID.getId(),
... ... @@ -92,9 +84,9 @@ public class ResourceDaoImpl implements ResourceDao {
92 84 }
93 85
94 86 @Override
95   - public List<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType,
96   - String[] objectIds,
97   - String searchText) {
  87 + public List<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType,
  88 + String[] objectIds,
  89 + String searchText) {
98 90 return objectIds == null ?
99 91 DaoUtil.convertDataList(resourceRepository.findResources(
100 92 tenantId.getId(),
... ... @@ -107,8 +99,4 @@ public class ResourceDaoImpl implements ResourceDao {
107 99 resourceType.name(), objectIds));
108 100 }
109 101
110   - @Override
111   - public void removeAllByTenantId(TenantId tenantId) {
112   - resourceRepository.removeAllByTenantId(tenantId.getId());
113   - }
114 102 }
... ...
  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.beans.factory.annotation.Autowired;
  20 +import org.springframework.data.repository.CrudRepository;
  21 +import org.springframework.stereotype.Component;
  22 +import org.thingsboard.server.common.data.TbResourceInfo;
  23 +import org.thingsboard.server.common.data.id.TenantId;
  24 +import org.thingsboard.server.common.data.page.PageData;
  25 +import org.thingsboard.server.common.data.page.PageLink;
  26 +import org.thingsboard.server.dao.DaoUtil;
  27 +import org.thingsboard.server.dao.model.sql.TbResourceInfoEntity;
  28 +import org.thingsboard.server.dao.resource.TbResourceInfoDao;
  29 +import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
  30 +
  31 +import java.util.Objects;
  32 +import java.util.UUID;
  33 +
  34 +@Slf4j
  35 +@Component
  36 +public class JpaTbResourceInfoDao extends JpaAbstractSearchTextDao<TbResourceInfoEntity, TbResourceInfo> implements TbResourceInfoDao {
  37 +
  38 + @Autowired
  39 + private TbResourceInfoRepository resourceInfoRepository;
  40 +
  41 + @Override
  42 + protected Class<TbResourceInfoEntity> getEntityClass() {
  43 + return TbResourceInfoEntity.class;
  44 + }
  45 +
  46 + @Override
  47 + protected CrudRepository<TbResourceInfoEntity, UUID> getCrudRepository() {
  48 + return resourceInfoRepository;
  49 + }
  50 +
  51 + @Override
  52 + public PageData<TbResourceInfo> findTbResourcesByTenantId(UUID tenantId, PageLink pageLink) {
  53 + return DaoUtil.toPageData(resourceInfoRepository
  54 + .findByTenantId(
  55 + tenantId,
  56 + TenantId.NULL_UUID,
  57 + Objects.toString(pageLink.getTextSearch(), ""),
  58 + DaoUtil.toPageable(pageLink))); }
  59 +}
... ...
  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.jpa.repository.Query;
  21 +import org.springframework.data.repository.CrudRepository;
  22 +import org.springframework.data.repository.query.Param;
  23 +import org.thingsboard.server.dao.model.sql.TbResourceInfoEntity;
  24 +
  25 +import java.util.UUID;
  26 +
  27 +public interface TbResourceInfoRepository extends CrudRepository<TbResourceInfoEntity, UUID> {
  28 +
  29 + @Query("SELECT tr FROM TbResourceInfoEntity tr WHERE tr.tenantId = :tenantId " +
  30 + "AND LOWER(tr.searchText) LIKE LOWER(CONCAT(:searchText, '%'))" +
  31 + "AND (tr.tenantId = :tenantId " +
  32 + "OR (tr.tenantId = :systemAdminId " +
  33 + "AND NOT EXISTS " +
  34 + "(SELECT sr FROM TbResourceEntity sr " +
  35 + "WHERE sr.tenantId = :tenantId " +
  36 + "AND tr.resourceType = sr.resourceType " +
  37 + "AND tr.resourceKey = sr.resourceKey)))")
  38 + Page<TbResourceInfoEntity> findByTenantId(@Param("tenantId") UUID tenantId,
  39 + @Param("systemAdminId") UUID sysadminId,
  40 + @Param("searchText") String searchText,
  41 + Pageable pageable);
  42 +}
... ...
dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java renamed from dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceRepository.java
... ... @@ -20,65 +20,63 @@ import org.springframework.data.domain.Pageable;
20 20 import org.springframework.data.jpa.repository.Query;
21 21 import org.springframework.data.repository.CrudRepository;
22 22 import org.springframework.data.repository.query.Param;
23   -import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
24   -import org.thingsboard.server.dao.model.sql.ResourceEntity;
  23 +import org.thingsboard.server.dao.model.sql.TbResourceEntity;
25 24
26 25 import java.util.List;
27 26 import java.util.UUID;
28 27
29   -public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> {
  28 +public interface TbResourceRepository extends CrudRepository<TbResourceEntity, UUID> {
30 29
  30 + TbResourceEntity findByTenantIdAndResourceTypeAndResourceKey(UUID tenantId, String resourceType, String resourceKey);
31 31
32   - Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable);
  32 + Page<TbResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable);
33 33
34   - @Query("SELECT tr FROM ResourceEntity tr " +
  34 + @Query("SELECT tr FROM TbResourceEntity tr " +
35 35 "WHERE tr.resourceType = :resourceType " +
36   - "AND LOWER(tr.textSearch) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
  36 + "AND LOWER(tr.searchText) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
37 37 "AND (tr.tenantId = :tenantId " +
38 38 "OR (tr.tenantId = :systemAdminId " +
39 39 "AND NOT EXISTS " +
40   - "(SELECT sr FROM ResourceEntity sr " +
  40 + "(SELECT sr FROM TbResourceEntity sr " +
41 41 "WHERE sr.tenantId = :tenantId " +
42 42 "AND sr.resourceType = :resourceType " +
43   - "AND tr.resourceId = sr.resourceId)))")
44   - Page<ResourceEntity> findResourcesPage(
  43 + "AND tr.resourceKey = sr.resourceKey)))")
  44 + Page<TbResourceEntity> findResourcesPage(
45 45 @Param("tenantId") UUID tenantId,
46 46 @Param("systemAdminId") UUID sysAdminId,
47 47 @Param("resourceType") String resourceType,
48 48 @Param("searchText") String search,
49 49 Pageable pageable);
50 50
51   - List<ResourceEntity> findAllByTenantIdAndResourceType(UUID tenantId, String resourceType);
52   -
53 51 void removeAllByTenantId(UUID tenantId);
54 52
55   - @Query("SELECT tr FROM ResourceEntity tr " +
  53 + @Query("SELECT tr FROM TbResourceEntity tr " +
56 54 "WHERE tr.resourceType = :resourceType " +
57   - "AND LOWER(tr.textSearch) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
  55 + "AND LOWER(tr.searchText) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
58 56 "AND (tr.tenantId = :tenantId " +
59 57 "OR (tr.tenantId = :systemAdminId " +
60 58 "AND NOT EXISTS " +
61   - "(SELECT sr FROM ResourceEntity sr " +
  59 + "(SELECT sr FROM TbResourceEntity sr " +
62 60 "WHERE sr.tenantId = :tenantId " +
63 61 "AND sr.resourceType = :resourceType " +
64   - "AND tr.resourceId = sr.resourceId)))")
65   - List<ResourceEntity> findResources(@Param("tenantId") UUID tenantId,
66   - @Param("systemAdminId") UUID sysAdminId,
67   - @Param("resourceType") String resourceType,
68   - @Param("searchText") String search);
  62 + "AND tr.resourceKey = sr.resourceKey)))")
  63 + List<TbResourceEntity> findResources(@Param("tenantId") UUID tenantId,
  64 + @Param("systemAdminId") UUID sysAdminId,
  65 + @Param("resourceType") String resourceType,
  66 + @Param("searchText") String search);
69 67
70   - @Query("SELECT tr FROM ResourceEntity tr " +
  68 + @Query("SELECT tr FROM TbResourceEntity tr " +
71 69 "WHERE tr.resourceType = :resourceType " +
72   - "AND tr.resourceId in (:resourceIds) " +
  70 + "AND tr.resourceKey in (:resourceIds) " +
73 71 "AND (tr.tenantId = :tenantId " +
74 72 "OR (tr.tenantId = :systemAdminId " +
75 73 "AND NOT EXISTS " +
76   - "(SELECT sr FROM ResourceEntity sr " +
  74 + "(SELECT sr FROM TbResourceEntity sr " +
77 75 "WHERE sr.tenantId = :tenantId " +
78 76 "AND sr.resourceType = :resourceType " +
79   - "AND tr.resourceId = sr.resourceId)))")
80   - List<ResourceEntity> findResourcesByIds(@Param("tenantId") UUID tenantId,
81   - @Param("systemAdminId") UUID sysAdminId,
82   - @Param("resourceType") String resourceType,
83   - @Param("resourceIds") String[] objectIds);
  77 + "AND tr.resourceKey = sr.resourceKey)))")
  78 + List<TbResourceEntity> findResourcesByIds(@Param("tenantId") UUID tenantId,
  79 + @Param("systemAdminId") UUID sysAdminId,
  80 + @Param("resourceType") String resourceType,
  81 + @Param("resourceIds") String[] objectIds);
84 82 }
... ...
... ... @@ -35,7 +35,7 @@ import org.thingsboard.server.dao.device.DeviceService;
35 35 import org.thingsboard.server.dao.entity.AbstractEntityService;
36 36 import org.thingsboard.server.dao.entityview.EntityViewService;
37 37 import org.thingsboard.server.dao.exception.DataValidationException;
38   -import org.thingsboard.server.dao.resource.ResourceService;
  38 +import org.thingsboard.server.dao.resource.TbResourceService;
39 39 import org.thingsboard.server.dao.rule.RuleChainService;
40 40 import org.thingsboard.server.dao.service.DataValidator;
41 41 import org.thingsboard.server.dao.service.PaginatedRemover;
... ... @@ -90,7 +90,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
90 90 private RuleChainService ruleChainService;
91 91
92 92 @Autowired
93   - private ResourceService resourceService;
  93 + private TbResourceService resourceService;
94 94
95 95 @Override
96 96 public Tenant findTenantById(TenantId tenantId) {
... ...
... ... @@ -426,10 +426,13 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
426 426 );
427 427
428 428 CREATE TABLE IF NOT EXISTS resource (
  429 + id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY,
  430 + created_time bigint NOT NULL,
429 431 tenant_id uuid NOT NULL,
  432 + title varchar(255) NOT NULL,
430 433 resource_type varchar(32) NOT NULL,
431   - resource_id varchar(255) NOT NULL,
432   - text_search varchar(255),
433   - resource_value varchar,
434   - CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)
  434 + resource_key varchar(255) NOT NULL,
  435 + search_text varchar(255),
  436 + data varchar,
  437 + CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
435 438 );
... ...
... ... @@ -452,12 +452,15 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
452 452 );
453 453
454 454 CREATE TABLE IF NOT EXISTS resource (
  455 + id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY,
  456 + created_time bigint NOT NULL,
455 457 tenant_id uuid NOT NULL,
  458 + title varchar(255) NOT NULL,
456 459 resource_type varchar(32) NOT NULL,
457   - resource_id varchar(255) NOT NULL,
458   - text_search varchar(255),
459   - resource_value varchar,
460   - CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)
  460 + resource_key varchar(255) NOT NULL,
  461 + search_text varchar(255),
  462 + data varchar,
  463 + CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
461 464 );
462 465
463 466 CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint)
... ...