Browse Source

TbResource extends SearchTextBased, created TbResourceInfo

pull/4286/head
YevhenBondarenko 5 years ago
committed by Andrew Shvayka
parent
commit
ad7c314b24
  1. 39
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  2. 86
      application/src/main/java/org/thingsboard/server/controller/TbResourceController.java
  3. 35
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  4. 19
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  5. 19
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  6. 6
      application/src/main/java/org/thingsboard/server/service/queue/TbClusterService.java
  7. 3
      application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
  8. 1
      application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java
  9. 16
      application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
  10. 14
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  11. 20
      common/dao-api/src/main/java/org/thingsboard/server/dao/resource/TbResourceService.java
  12. 2
      common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
  13. 46
      common/data/src/main/java/org/thingsboard/server/common/data/Resource.java
  14. 69
      common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java
  15. 74
      common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java
  16. 2
      common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java
  17. 39
      common/data/src/main/java/org/thingsboard/server/common/data/id/TbResourceId.java
  18. 6
      common/queue/src/main/proto/queue.proto
  19. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java
  20. 4
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportResourceCache.java
  21. 66
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java
  22. 4
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  23. 6
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  24. 44
      dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceCompositeKey.java
  25. 95
      dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java
  26. 65
      dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java
  27. 124
      dao/src/main/java/org/thingsboard/server/dao/resource/BaseTbResourceService.java
  28. 47
      dao/src/main/java/org/thingsboard/server/dao/resource/ResourceDao.java
  29. 43
      dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java
  30. 29
      dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java
  31. 64
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java
  32. 59
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java
  33. 42
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceInfoRepository.java
  34. 52
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java
  35. 4
      dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java
  36. 11
      dao/src/main/resources/sql/schema-entities-hsql.sql
  37. 11
      dao/src/main/resources/sql/schema-entities.sql

39
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -39,6 +39,8 @@ import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantInfo;
import org.thingsboard.server.common.data.TenantProfile;
@ -59,6 +61,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
@ -77,7 +80,6 @@ import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.common.msg.TbMsg;
@ -99,6 +101,7 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
import org.thingsboard.server.dao.oauth2.OAuth2Service;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.TbResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantProfileService;
@ -226,6 +229,9 @@ public abstract class BaseController {
@Autowired
protected PartitionService partitionService;
@Autowired
protected TbResourceService resourceService;
@Autowired
protected TbQueueProducerProvider producerProvider;
@ -461,6 +467,9 @@ public abstract class BaseController {
case WIDGET_TYPE:
checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation);
return;
case TB_RESOURCE:
checkResourceId(new TbResourceId(entityId.getId()), operation);
return;
default:
throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
}
@ -668,6 +677,30 @@ public abstract class BaseController {
return ruleNode;
}
TbResource checkResourceId(TbResourceId resourceId, Operation operation) throws ThingsboardException {
try {
validateId(resourceId, "Incorrect resourceId " + resourceId);
TbResource resource = resourceService.findResourceById(getCurrentUser().getTenantId(), resourceId);
checkNotNull(resource);
accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resource);
return resource;
} catch (Exception e) {
throw handleException(e, false);
}
}
TbResourceInfo checkResourceInfoId(TbResourceId resourceId, Operation operation) throws ThingsboardException {
try {
validateId(resourceId, "Incorrect resourceId " + resourceId);
TbResourceInfo resourceInfo = resourceService.findResourceInfoById(getCurrentUser().getTenantId(), resourceId);
checkNotNull(resourceInfo);
accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resourceInfo);
return resourceInfo;
} catch (Exception e) {
throw handleException(e, false);
}
}
@SuppressWarnings("unchecked")
protected <I extends EntityId> I emptyId(EntityType entityType) {
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
@ -884,8 +917,8 @@ public abstract class BaseController {
protected void processDashboardIdFromAdditionalInfo(ObjectNode additionalInfo, String requiredFields) throws ThingsboardException {
String dashboardId = additionalInfo.has(requiredFields) ? additionalInfo.get(requiredFields).asText() : null;
if(dashboardId != null && !dashboardId.equals("null")) {
if(dashboardService.findDashboardById(getTenantId(), new DashboardId(UUID.fromString(dashboardId))) == null) {
if (dashboardId != null && !dashboardId.equals("null")) {
if (dashboardService.findDashboardById(getTenantId(), new DashboardId(UUID.fromString(dashboardId))) == null) {
additionalInfo.remove(requiredFields);
}
}

86
application/src/main/java/org/thingsboard/server/controller/ResourceController.java → application/src/main/java/org/thingsboard/server/controller/TbResourceController.java

@ -18,20 +18,23 @@ package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.resource.TbResourceService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import java.util.List;
@ -39,21 +42,50 @@ import java.util.List;
@RestController
@TbCoreComponent
@RequestMapping("/api")
public class ResourceController extends BaseController {
public class TbResourceController extends BaseController {
private final ResourceService resourceService;
public static final String RESOURCE_ID = "resourceId";
public ResourceController(ResourceService resourceService) {
private final TbResourceService resourceService;
public TbResourceController(TbResourceService resourceService) {
this.resourceService = resourceService;
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/info/{resourceId}", method = RequestMethod.GET)
@ResponseBody
public TbResourceInfo getResourceInfoById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
try {
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
return checkResourceInfoId(resourceId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.GET)
@ResponseBody
public TbResource getResourceById(@PathVariable(RESOURCE_ID) String strResourceId) throws ThingsboardException {
checkParameter(RESOURCE_ID, strResourceId);
try {
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
return checkResourceId(resourceId, Operation.READ);
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource", method = RequestMethod.POST)
@ResponseBody
public Resource saveResource(Resource resource) throws ThingsboardException {
public TbResource saveResource(@RequestBody TbResource resource) throws ThingsboardException {
try {
resource.setTenantId(getTenantId());
Resource savedResource = checkNotNull(resourceService.saveResource(resource));
checkEntity(resource.getId(), resource, Resource.TB_RESOURCE);
TbResource savedResource = checkNotNull(resourceService.saveResource(resource));
tbClusterService.onResourceChange(savedResource, null);
return savedResource;
} catch (Exception e) {
@ -64,15 +96,14 @@ public class ResourceController extends BaseController {
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource", method = RequestMethod.GET)
@ResponseBody
public PageData<Resource> getResources(@RequestParam(required = false) boolean system,
@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
public PageData<TbResourceInfo> getResources(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
return checkNotNull(resourceService.findResourcesByTenantId(system ? TenantId.SYS_TENANT_ID : getTenantId(), pageLink));
return checkNotNull(resourceService.findResourcesByTenantId(getTenantId(), pageLink));
} catch (Exception e) {
throw handleException(e);
}
@ -82,10 +113,10 @@ public class ResourceController extends BaseController {
@RequestMapping(value = "/resource/lwm2m/page", method = RequestMethod.GET)
@ResponseBody
public List<LwM2mObject> getLwm2mListObjectsPage(@RequestParam int pageSize,
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
@RequestParam int page,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String sortProperty,
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
try {
PageLink pageLink = new PageLink(pageSize, page, textSearch);
return checkNotNull(resourceService.findLwM2mObjectPage(getTenantId(), sortProperty, sortOrder, pageLink));
@ -95,7 +126,7 @@ public class ResourceController extends BaseController {
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET)
@RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET)
@ResponseBody
public List<LwM2mObject> getLwm2mListObjects(@RequestParam String sortOrder,
@RequestParam String sortProperty,
@ -108,14 +139,15 @@ public class ResourceController extends BaseController {
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(value = "/resource/{resourceType}/{resourceId}", method = RequestMethod.DELETE)
@RequestMapping(value = "/resource/{resourceId}", method = RequestMethod.DELETE)
@ResponseBody
public void deleteResource(@PathVariable("resourceType") ResourceType resourceType,
@PathVariable("resourceId") String resourceId) throws ThingsboardException {
public void deleteResource(@PathVariable("resourceId") String strResourceId) throws ThingsboardException {
checkParameter("resourceId", strResourceId);
try {
Resource resource = checkNotNull(resourceService.getResource(getTenantId(), resourceType, resourceId));
resourceService.deleteResource(getTenantId(), resourceType, resourceId);
tbClusterService.onResourceDeleted(resource, null);
TbResourceId resourceId = new TbResourceId(toUUID(strResourceId));
TbResource tbResource = checkResourceId(resourceId, Operation.DELETE);
resourceService.deleteResource(getTenantId(), resourceId);
tbClusterService.onResourceDeleted(tbResource, null);
} catch (Exception e) {
throw handleException(e);
}

35
application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java

@ -22,8 +22,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.resource.TbResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
@ -95,7 +95,7 @@ public class InstallScripts {
private OAuth2ConfigTemplateService oAuth2TemplateService;
@Autowired
private ResourceService resourceService;
private TbResourceService resourceService;
public Path getTenantRuleChainsDir() {
return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
@ -204,13 +204,10 @@ public class InstallScripts {
path -> {
try {
byte[] fileBytes = Files.readAllBytes(path);
String source = new String(fileBytes);
Resource resource = new Resource();
TbResource resource = new TbResource();
resource.setTenantId(TenantId.SYS_TENANT_ID);
resource.setResourceType(ResourceType.LWM2M_MODEL);
resource.setResourceId(getValueByTag(source, "ObjectID") + "_" + getValueByTag(source, "ObjectVersion"));
resource.setTextSearch(resource.getResourceId() + ":" + getValueByTag(source, "Name"));
resource.setValue(Base64.getEncoder().encodeToString(fileBytes));
resource.setData(Base64.getEncoder().encodeToString(fileBytes));
resourceService.saveResource(resource);
} catch (Exception e) {
throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", path.toString()));
@ -219,28 +216,6 @@ public class InstallScripts {
);
}
}
Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks");
try {
Resource resource = new Resource();
resource.setTenantId(TenantId.SYS_TENANT_ID);
resource.setResourceType(ResourceType.JKS);
resource.setResourceId(jksPath.getFileName().toString());
resource.setTextSearch(jksPath.getFileName().toString());
resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
resourceService.saveResource(resource);
} catch (Exception e) {
log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
throw new RuntimeException("Unable to load lwm2m serverKeyStore", e);
}
}
private String getValueByTag(String source, String tag) {
int lenTag = ("<" + tag + ">").length();
int indStart = source.indexOf("<" + tag + ">");
int indEnd = source.indexOf("</" + tag + ">");
return (indStart > 0 && indEnd > 0) ? source.substring(indStart + lenTag, indEnd) : null;
}
public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {

19
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -450,14 +450,17 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Updating schema ...");
try {
conn.createStatement().execute("CREATE TABLE IF NOT EXISTS resource (" +
" tenant_id uuid NOT NULL," +
" resource_type varchar(32) NOT NULL," +
" resource_id varchar(255) NOT NULL," +
" text_search varchar(255)," +
" resource_value varchar," +
" CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)" +
" );");
conn.createStatement().execute("CREATE TABLE IF NOT EXISTS resource ( " +
"id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY, " +
"created_time bigint NOT NULL, " +
"tenant_id uuid NOT NULL, " +
"title varchar(255) NOT NULL, " +
"resource_type varchar(32) NOT NULL, " +
"resource_key varchar(255) NOT NULL, " +
"search_text varchar(255), " +
"data varchar, " +
"CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)" +
");");
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;");
installScripts.loadSystemLwm2mResources();

19
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java

@ -26,7 +26,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.DeviceId;
@ -249,28 +249,27 @@ public class DefaultTbClusterService implements TbClusterService {
}
@Override
public void onResourceChange(Resource resource, TbQueueCallback callback) {
public void onResourceChange(TbResource resource, TbQueueCallback callback) {
TenantId tenantId = resource.getTenantId();
log.trace("[{}][{}][{}] Processing change resource", tenantId, resource.getResourceType(), resource.getResourceId());
log.trace("[{}][{}][{}] Processing change resource", tenantId, resource.getResourceType(), resource.getResourceKey());
TransportProtos.ResourceUpdateMsg resourceUpdateMsg = TransportProtos.ResourceUpdateMsg.newBuilder()
.setTenantIdMSB(tenantId.getId().getMostSignificantBits())
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
.setResourceType(resource.getResourceType().name())
.setResourceId(resource.getResourceId())
.setResourceKey(resource.getResourceKey())
.build();
ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setResourceUpdateMsg(resourceUpdateMsg).build();
broadcast(transportMsg, callback);
}
@Override
public void onResourceDeleted(Resource resource, TbQueueCallback callback) {
TenantId tenantId = resource.getTenantId();
log.trace("[{}][{}][{}] Processing delete resource", tenantId, resource.getResourceType(), resource.getResourceId());
public void onResourceDeleted(TbResource resource, TbQueueCallback callback) {
log.trace("[{}] Processing delete resource", resource);
TransportProtos.ResourceDeleteMsg resourceUpdateMsg = TransportProtos.ResourceDeleteMsg.newBuilder()
.setTenantIdMSB(tenantId.getId().getMostSignificantBits())
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
.setTenantIdMSB(resource.getTenantId().getId().getMostSignificantBits())
.setTenantIdLSB(resource.getTenantId().getId().getLeastSignificantBits())
.setResourceType(resource.getResourceType().name())
.setResourceId(resource.getResourceId())
.setResourceKey(resource.getResourceKey())
.build();
ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setResourceDeleteMsg(resourceUpdateMsg).build();
broadcast(transportMsg, callback);

6
application/src/main/java/org/thingsboard/server/service/queue/TbClusterService.java

@ -19,7 +19,7 @@ import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.EntityId;
@ -73,7 +73,7 @@ public interface TbClusterService {
void onDeviceDeleted(Device device, TbQueueCallback callback);
void onResourceChange(Resource resource, TbQueueCallback callback);
void onResourceChange(TbResource resource, TbQueueCallback callback);
void onResourceDeleted(Resource resource, TbQueueCallback callback);
void onResourceDeleted(TbResource resource, TbQueueCallback callback);
}

3
application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java

@ -36,7 +36,8 @@ public enum Resource {
OAUTH2_CONFIGURATION_TEMPLATE(),
TENANT_PROFILE(EntityType.TENANT_PROFILE),
DEVICE_PROFILE(EntityType.DEVICE_PROFILE),
API_USAGE_STATE(EntityType.API_USAGE_STATE);
API_USAGE_STATE(EntityType.API_USAGE_STATE),
TB_RESOURCE(EntityType.TB_RESOURCE);
private final EntityType entityType;

1
application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java

@ -38,6 +38,7 @@ public class SysAdminPermissions extends AbstractPermissions {
put(Resource.OAUTH2_CONFIGURATION_INFO, PermissionChecker.allowAllPermissionChecker);
put(Resource.OAUTH2_CONFIGURATION_TEMPLATE, PermissionChecker.allowAllPermissionChecker);
put(Resource.TENANT_PROFILE, PermissionChecker.allowAllPermissionChecker);
put(Resource.TB_RESOURCE, systemEntityPermissionChecker);
}
private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker() {

16
application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java

@ -41,6 +41,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
put(Resource.DEVICE_PROFILE, tenantEntityPermissionChecker);
put(Resource.API_USAGE_STATE, tenantEntityPermissionChecker);
put(Resource.TB_RESOURCE, tbResourcePermissionChecker);
}
public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() {
@ -101,4 +102,19 @@ public class TenantAdminPermissions extends AbstractPermissions {
}
};
private static final PermissionChecker tbResourcePermissionChecker = new PermissionChecker() {
@Override
public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) {
if (entity.getTenantId() == null || entity.getTenantId().isNullUid()) {
return operation == Operation.READ;
}
if (!user.getTenantId().equals(entity.getTenantId())) {
return false;
}
return true;
}
};
}

14
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
@ -56,7 +56,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
import org.thingsboard.server.dao.device.provision.ProvisionRequest;
import org.thingsboard.server.dao.device.provision.ProvisionResponse;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.resource.TbResourceService;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
@ -108,7 +108,7 @@ public class DefaultTransportApiService implements TransportApiService {
private final TbClusterService tbClusterService;
private final DataDecodingEncodingService dataDecodingEncodingService;
private final DeviceProvisionService deviceProvisionService;
private final ResourceService resourceService;
private final TbResourceService resourceService;
private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
@ -117,7 +117,7 @@ public class DefaultTransportApiService implements TransportApiService {
RelationService relationService, DeviceCredentialsService deviceCredentialsService,
DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
DeviceProvisionService deviceProvisionService, ResourceService resourceService) {
DeviceProvisionService deviceProvisionService, TbResourceService resourceService) {
this.deviceProfileCache = deviceProfileCache;
this.tenantProfileCache = tenantProfileCache;
this.apiUsageStateService = apiUsageStateService;
@ -365,12 +365,12 @@ public class DefaultTransportApiService implements TransportApiService {
private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) {
TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType());
String resourceId = requestMsg.getResourceId();
String resourceKey = requestMsg.getResourceKey();
TransportProtos.GetResourceResponseMsg.Builder builder = TransportProtos.GetResourceResponseMsg.newBuilder();
Resource resource = resourceService.getResource(tenantId, resourceType, resourceId);
TbResource resource = resourceService.getResource(tenantId, resourceType, resourceKey);
if (resource == null && !tenantId.equals(TenantId.SYS_TENANT_ID)) {
resource = resourceService.getResource(TenantId.SYS_TENANT_ID, resourceType, resourceId);
resource = resourceService.getResource(TenantId.SYS_TENANT_ID, resourceType, resourceKey);
}
if (resource != null) {

20
common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java → common/dao-api/src/main/java/org/thingsboard/server/dao/resource/TbResourceService.java

@ -15,24 +15,30 @@
*/
package org.thingsboard.server.dao.resource;
import org.thingsboard.server.common.data.Resource;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.io.IOException;
import java.util.List;
public interface ResourceService {
Resource saveResource(Resource resource);
public interface TbResourceService {
TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException;
Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
TbResource findResourceById(TenantId tenantId, TbResourceId resourceId);
List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType);
TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId);
PageData<TbResourceInfo> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
List<LwM2mObject> findLwM2mObject(TenantId tenantId,
String sortOrder,
@ -44,7 +50,7 @@ public interface ResourceService {
String sortOrder,
PageLink pageLink);
void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
void deleteResource(TenantId tenantId, TbResourceId resourceId);
void deleteResourcesByTenantId(TenantId tenantId);
}

2
common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java

@ -19,5 +19,5 @@ package org.thingsboard.server.common.data;
* @author Andrew Shvayka
*/
public enum EntityType {
TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE, TENANT_PROFILE, DEVICE_PROFILE, API_USAGE_STATE;
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;
}

46
common/data/src/main/java/org/thingsboard/server/common/data/Resource.java

@ -1,46 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TenantId;
import java.io.Serializable;
@Slf4j
@Data
public class Resource implements HasTenantId, Serializable {
private static final long serialVersionUID = 7379609705527272306L;
private TenantId tenantId;
private ResourceType resourceType;
private String resourceId;
private String textSearch;
private String value;
@Override
public String toString() {
final StringBuilder res = new StringBuilder("Resource{");
res.append("tenantId=").append(tenantId);
res.append(", resourceType='").append(resourceType).append('\'');
res.append(", resourceId='").append(resourceId).append('\'');
res.append(", textSearch='").append(textSearch).append('\'');
res.append('}');
return res.toString();
}
}

69
common/data/src/main/java/org/thingsboard/server/common/data/TbResource.java

@ -0,0 +1,69 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TbResourceId;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class TbResource extends TbResourceInfo {
private static final long serialVersionUID = 7379609705527272306L;
private String data;
public TbResource() {
super();
}
public TbResource(TbResourceId id) {
super(id);
}
public TbResource(TbResourceInfo resourceInfo) {
super(resourceInfo);
}
public TbResource(TbResource resource) {
super(resource);
this.data = resource.getData();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Resource [tenantId=");
builder.append(getTenantId());
builder.append(", id=");
builder.append(getUuidId());
builder.append(", createdTime=");
builder.append(createdTime);
builder.append(", title=");
builder.append(getTitle());
builder.append(", resourceType=");
builder.append(getResourceType());
builder.append(", resourceKey=");
builder.append(getResourceKey());
builder.append(", data=");
builder.append(data);
builder.append("]");
return builder.toString();
}
}

74
common/data/src/main/java/org/thingsboard/server/common/data/TbResourceInfo.java

@ -0,0 +1,74 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class TbResourceInfo extends SearchTextBased<TbResourceId> implements HasTenantId {
private TenantId tenantId;
private String title;
private ResourceType resourceType;
private String resourceKey;
private String searchText;
public TbResourceInfo() {
super();
}
public TbResourceInfo(TbResourceId id) {
super(id);
}
public TbResourceInfo(TbResourceInfo resourceInfo) {
super(resourceInfo);
this.tenantId = resourceInfo.getTenantId();
this.title = resourceInfo.getTitle();
this.resourceType = resourceInfo.getResourceType();
this.resourceKey = resourceInfo.resourceKey;
}
@Override
public String getSearchText() {
return searchText;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ResourceInfo [tenantId=");
builder.append(tenantId);
builder.append(", id=");
builder.append(getUuidId());
builder.append(", createdTime=");
builder.append(createdTime);
builder.append(", title=");
builder.append(title);
builder.append(", resourceType=");
builder.append(resourceType);
builder.append(", resourceKey=");
builder.append(resourceKey);
builder.append("]");
return builder.toString();
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java

@ -68,6 +68,8 @@ public class EntityIdFactory {
return new TenantProfileId(uuid);
case API_USAGE_STATE:
return new ApiUsageStateId(uuid);
case TB_RESOURCE:
return new TbResourceId(uuid);
}
throw new IllegalArgumentException("EntityType " + type + " is not supported!");
}

39
common/data/src/main/java/org/thingsboard/server/common/data/id/TbResourceId.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
public class TbResourceId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@JsonCreator
public TbResourceId(@JsonProperty("id") UUID id) {
super(id);
}
@JsonIgnore
@Override
public EntityType getEntityType() {
return EntityType.TB_RESOURCE;
}
}

6
common/queue/src/main/proto/queue.proto

@ -205,7 +205,7 @@ message GetResourceRequestMsg {
int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2;
string resourceType = 3;
string resourceId = 4;
string resourceKey = 4;
}
message GetResourceResponseMsg {
@ -257,14 +257,14 @@ message ResourceUpdateMsg {
int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2;
string resourceType = 3;
string resourceId = 4;
string resourceKey = 4;
}
message ResourceDeleteMsg {
int64 tenantIdMSB = 1;
int64 tenantIdLSB = 2;
string resourceType = 3;
string resourceId = 4;
string resourceKey = 4;
}
message SessionCloseNotificationProto {

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java

@ -124,7 +124,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
this.tenantId,
LWM2M_MODEL,
key).
getValue();
getData();
return xmlB64 != null && !xmlB64.isEmpty() ?
lwM2mTransportContextServer.parseFromXmlToObjectModel(
Base64.getDecoder().decode(xmlB64),

4
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportResourceCache.java

@ -15,13 +15,13 @@
*/
package org.thingsboard.server.common.transport;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId;
public interface TransportResourceCache {
Resource get(TenantId tenantId, ResourceType resourceType, String resourceId);
TbResource get(TenantId tenantId, ResourceType resourceType, String resourceId);
void update(TenantId tenantId, ResourceType resourceType, String resourceI);

66
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java

@ -19,7 +19,7 @@ import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.TransportResourceCache;
@ -42,8 +42,8 @@ import java.util.concurrent.locks.ReentrantLock;
public class DefaultTransportResourceCache implements TransportResourceCache {
private final Lock resourceFetchLock = new ReentrantLock();
private final ConcurrentMap<ResourceKey, Resource> resources = new ConcurrentHashMap<>();
private final Set<ResourceKey> keys = ConcurrentHashMap.newKeySet();
private final ConcurrentMap<ResourceCompositeKey, TbResource> resources = new ConcurrentHashMap<>();
private final Set<ResourceCompositeKey> keys = ConcurrentHashMap.newKeySet();
private final DataDecodingEncodingService dataDecodingEncodingService;
private final TransportService transportService;
@ -53,26 +53,26 @@ public class DefaultTransportResourceCache implements TransportResourceCache {
}
@Override
public Resource get(TenantId tenantId, ResourceType resourceType, String resourceId) {
ResourceKey resourceKey = new ResourceKey(tenantId, resourceType, resourceId);
Resource resource;
public TbResource get(TenantId tenantId, ResourceType resourceType, String resourceKey) {
ResourceCompositeKey compositeKey = new ResourceCompositeKey(tenantId, resourceType, resourceKey);
TbResource resource;
if (keys.contains(resourceKey)) {
resource = resources.get(resourceKey);
if (keys.contains(compositeKey)) {
resource = resources.get(compositeKey);
if (resource == null) {
resource = resources.get(resourceKey.getSystemKey());
resource = resources.get(compositeKey.getSystemKey());
}
} else {
resourceFetchLock.lock();
try {
if (keys.contains(resourceKey)) {
resource = resources.get(resourceKey);
if (keys.contains(compositeKey)) {
resource = resources.get(compositeKey);
if (resource == null) {
resource = resources.get(resourceKey.getSystemKey());
resource = resources.get(compositeKey.getSystemKey());
}
} else {
resource = fetchResource(resourceKey);
keys.add(resourceKey);
resource = fetchResource(compositeKey);
keys.add(compositeKey);
}
} finally {
resourceFetchLock.unlock();
@ -82,20 +82,20 @@ public class DefaultTransportResourceCache implements TransportResourceCache {
return resource;
}
private Resource fetchResource(ResourceKey resourceKey) {
UUID tenantId = resourceKey.getTenantId().getId();
private TbResource fetchResource(ResourceCompositeKey compositeKey) {
UUID tenantId = compositeKey.getTenantId().getId();
TransportProtos.GetResourceRequestMsg.Builder builder = TransportProtos.GetResourceRequestMsg.newBuilder();
builder
.setTenantIdLSB(tenantId.getLeastSignificantBits())
.setTenantIdMSB(tenantId.getMostSignificantBits())
.setResourceType(resourceKey.resourceType.name())
.setResourceId(resourceKey.resourceId);
.setResourceType(compositeKey.resourceType.name())
.setResourceKey(compositeKey.resourceKey);
TransportProtos.GetResourceResponseMsg responseMsg = transportService.getResource(builder.build());
Optional<Resource> optionalResource = dataDecodingEncodingService.decode(responseMsg.getResource().toByteArray());
Optional<TbResource> optionalResource = dataDecodingEncodingService.decode(responseMsg.getResource().toByteArray());
if (optionalResource.isPresent()) {
Resource resource = optionalResource.get();
resources.put(new ResourceKey(resource.getTenantId(), resource.getResourceType(), resource.getResourceId()), resource);
TbResource resource = optionalResource.get();
resources.put(new ResourceCompositeKey(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey()), resource);
return resource;
}
@ -103,28 +103,28 @@ public class DefaultTransportResourceCache implements TransportResourceCache {
}
@Override
public void update(TenantId tenantId, ResourceType resourceType, String resourceId) {
ResourceKey resourceKey = new ResourceKey(tenantId, resourceType, resourceId);
if (keys.contains(resourceKey) || resources.containsKey(resourceKey)) {
fetchResource(resourceKey);
public void update(TenantId tenantId, ResourceType resourceType, String resourceKey) {
ResourceCompositeKey compositeKey = new ResourceCompositeKey(tenantId, resourceType, resourceKey);
if (keys.contains(compositeKey) || resources.containsKey(compositeKey)) {
fetchResource(compositeKey);
}
}
@Override
public void evict(TenantId tenantId, ResourceType resourceType, String resourceId) {
ResourceKey resourceKey = new ResourceKey(tenantId, resourceType, resourceId);
keys.remove(resourceKey);
resources.remove(resourceKey);
public void evict(TenantId tenantId, ResourceType resourceType, String resourceKey) {
ResourceCompositeKey compositeKey = new ResourceCompositeKey(tenantId, resourceType, resourceKey);
keys.remove(compositeKey);
resources.remove(compositeKey);
}
@Data
private static class ResourceKey {
private static class ResourceCompositeKey {
private final TenantId tenantId;
private final ResourceType resourceType;
private final String resourceId;
private final String resourceKey;
public ResourceKey getSystemKey() {
return new ResourceKey(TenantId.SYS_TENANT_ID, resourceType, resourceId);
public ResourceCompositeKey getSystemKey() {
return new ResourceCompositeKey(TenantId.SYS_TENANT_ID, resourceType, resourceKey);
}
}
}

4
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -708,13 +708,13 @@ public class DefaultTransportService implements TransportService {
TransportProtos.ResourceUpdateMsg msg = toSessionMsg.getResourceUpdateMsg();
TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
ResourceType resourceType = ResourceType.valueOf(msg.getResourceType());
String resourceId = msg.getResourceId();
String resourceId = msg.getResourceKey();
transportResourceCache.update(tenantId, resourceType, resourceId);
} else if (toSessionMsg.hasResourceDeleteMsg()) {
TransportProtos.ResourceDeleteMsg msg = toSessionMsg.getResourceDeleteMsg();
TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB()));
ResourceType resourceType = ResourceType.valueOf(msg.getResourceType());
String resourceId = msg.getResourceId();
String resourceId = msg.getResourceKey();
transportResourceCache.evict(tenantId, resourceType, resourceId);
} else {
//TODO: should we notify the device actor about missed session?

6
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -462,9 +462,9 @@ public class ModelConstants {
public static final String RESOURCE_TABLE_NAME = "resource";
public static final String RESOURCE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
public static final String RESOURCE_TYPE_COLUMN = "resource_type";
public static final String RESOURCE_ID_COLUMN = "resource_id";
public static final String TEXT_SEARCH_COLUMN = "text_search";
public static final String RESOURCE_VALUE_COLUMN = "resource_value";
public static final String RESOURCE_KEY_COLUMN = "resource_key";
public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY;
public static final String RESOURCE_DATA_COLUMN = "data";
/**

44
dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceCompositeKey.java

@ -1,44 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.Resource;
import javax.persistence.Transient;
import java.io.Serializable;
import java.util.UUID;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ResourceCompositeKey implements Serializable {
@Transient
private static final long serialVersionUID = -3789469030818742769L;
private UUID tenantId;
private String resourceType;
private String resourceId;
public ResourceCompositeKey(Resource resource) {
this.tenantId = resource.getTenantId().getId();
this.resourceType = resource.getResourceType().name();
this.resourceId = resource.getResourceId();
}
}

95
dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java

@ -0,0 +1,95 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.SearchTextEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_DATA_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TITLE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = RESOURCE_TABLE_NAME)
public class TbResourceEntity extends BaseSqlEntity<TbResource> implements SearchTextEntity<TbResource> {
@Column(name = RESOURCE_TENANT_ID_COLUMN, columnDefinition = "uuid")
private UUID tenantId;
@Column(name = RESOURCE_TITLE_COLUMN)
private String title;
@Column(name = RESOURCE_TYPE_COLUMN)
private String resourceType;
@Column(name = RESOURCE_KEY_COLUMN)
private String resourceKey;
@Column(name = SEARCH_TEXT_PROPERTY)
private String searchText;
@Column(name = RESOURCE_DATA_COLUMN)
private String data;
public TbResourceEntity() {
}
public TbResourceEntity(TbResource resource) {
this.setUuid(resource.getId().getId());
this.tenantId = resource.getTenantId().getId();
this.title = resource.getTitle();
this.resourceType = resource.getResourceType().name();
this.resourceKey = resource.getResourceKey();
this.searchText = resource.getSearchText();
this.data = resource.getData();
}
@Override
public TbResource toData() {
TbResource resource = new TbResource();
resource.setId(new TbResourceId(id));
resource.setCreatedTime(createdTime);
resource.setTenantId(new TenantId(tenantId));
resource.setTitle(title);
resource.setResourceType(ResourceType.valueOf(resourceType));
resource.setResourceKey(resourceKey);
resource.setSearchText(searchText);
resource.setData(data);
return resource;
}
@Override
public String getSearchTextSource() {
return title;
}
}

65
dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceEntity.java → dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceInfoEntity.java

@ -16,68 +16,75 @@
package org.thingsboard.server.dao.model.sql;
import lombok.Data;
import org.thingsboard.server.common.data.Resource;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.ToData;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.model.SearchTextEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_KEY_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TITLE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_VALUE_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.TEXT_SEARCH_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.SEARCH_TEXT_PROPERTY;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = RESOURCE_TABLE_NAME)
@IdClass(ResourceCompositeKey.class)
public class ResourceEntity implements ToData<Resource> {
public class TbResourceInfoEntity extends BaseSqlEntity<TbResourceInfo> implements SearchTextEntity<TbResourceInfo> {
@Id
@Column(name = RESOURCE_TENANT_ID_COLUMN, columnDefinition = "uuid")
private UUID tenantId;
@Id
@Column(name = RESOURCE_TITLE_COLUMN)
private String title;
@Column(name = RESOURCE_TYPE_COLUMN)
private String resourceType;
@Id
@Column(name = RESOURCE_ID_COLUMN)
private String resourceId;
@Column(name = TEXT_SEARCH_COLUMN)
private String textSearch;
@Column(name = RESOURCE_KEY_COLUMN)
private String resourceKey;
@Column(name = RESOURCE_VALUE_COLUMN)
private String value;
@Column(name = SEARCH_TEXT_PROPERTY)
private String searchText;
public ResourceEntity() {
public TbResourceInfoEntity() {
}
public ResourceEntity(Resource resource) {
public TbResourceInfoEntity(TbResourceInfo resource) {
this.setUuid(resource.getId().getId());
this.setCreatedTime(resource.getCreatedTime());
this.tenantId = resource.getTenantId().getId();
this.title = resource.getTitle();
this.resourceType = resource.getResourceType().name();
this.resourceId = resource.getResourceId();
this.textSearch = resource.getTextSearch();
this.value = resource.getValue();
this.resourceKey = resource.getResourceKey();
this.searchText = resource.getSearchText();
}
@Override
public Resource toData() {
Resource resource = new Resource();
public TbResourceInfo toData() {
TbResourceInfo resource = new TbResourceInfo();
resource.setId(new TbResourceId(id));
resource.setCreatedTime(createdTime);
resource.setTenantId(new TenantId(tenantId));
resource.setTitle(title);
resource.setResourceType(ResourceType.valueOf(resourceType));
resource.setResourceId(resourceId);
resource.setTextSearch(textSearch);
resource.setValue(value);
resource.setResourceKey(resourceKey);
resource.setSearchText(searchText);
return resource;
}
@Override
public String getSearchTextSource() {
return title;
}
}

124
dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java → dao/src/main/java/org/thingsboard/server/dao/resource/BaseTbResourceService.java

@ -21,8 +21,10 @@ import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
import org.eclipse.leshan.core.model.ObjectModel;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.lwm2m.LwM2mInstance;
import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
@ -30,6 +32,8 @@ import org.thingsboard.server.common.data.lwm2m.LwM2mResource;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -44,61 +48,88 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
@Service
@Slf4j
public class BaseResourceService implements ResourceService {
public class BaseTbResourceService implements TbResourceService {
private final ResourceDao resourceDao;
public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId ";
private final TbResourceDao resourceDao;
private final TbResourceInfoDao resourceInfoDao;
private final DDFFileParser ddfFileParser;
public BaseResourceService(ResourceDao resourceDao) {
public BaseTbResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao) {
this.resourceDao = resourceDao;
this.resourceInfoDao = resourceInfoDao;
this.ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
}
@Override
public Resource saveResource(Resource resource) {
public TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException {
log.trace("Executing saveResource [{}]", resource);
if (resource.getId() == null && ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) {
List<ObjectModel> objectModels =
ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
if (!objectModels.isEmpty()) {
ObjectModel objectModel = objectModels.get(0);
String resourceKey = objectModel.id + "_" + objectModel.getVersion();
String name = objectModel.name;
resource.setResourceKey(resourceKey);
resource.setTitle(name);
resource.setSearchText(resourceKey + ":" + name);
}
}
validate(resource);
return resourceDao.saveResource(resource);
}
@Override
public Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceId);
validate(tenantId, resourceType, resourceId);
return resourceDao.getResource(tenantId, resourceType, resourceId);
public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {
log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceKey);
validate(tenantId, resourceType, resourceKey);
return resourceDao.getResource(tenantId, resourceType, resourceKey);
}
@Override
public void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
log.trace("Executing deleteResource [{}] [{}] [{}]", tenantId, resourceType, resourceId);
validate(tenantId, resourceType, resourceId);
resourceDao.deleteResource(tenantId, resourceType, resourceId);
public TbResource findResourceById(TenantId tenantId, TbResourceId resourceId) {
log.trace("Executing findResourceById [{}] [{}]", tenantId, resourceId);
Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
return resourceDao.findById(tenantId, resourceId.getId());
}
@Override
public PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
return resourceDao.findAllByTenantId(tenantId, pageLink);
public TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId) {
log.trace("Executing findResourceInfoById [{}] [{}]", tenantId, resourceId);
Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
return resourceInfoDao.findById(tenantId, resourceId.getId());
}
@Override
public void deleteResource(TenantId tenantId, TbResourceId resourceId) {
log.trace("Executing deleteResource [{}] [{}]", tenantId, resourceId);
Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
resourceDao.removeById(tenantId, resourceId.getId());
}
@Override
public List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType) {
public PageData<TbResourceInfo> findResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
return resourceDao.findAllByTenantIdAndResourceType(tenantId, resourceType);
return resourceInfoDao.findTbResourcesByTenantId(tenantId.getId(), pageLink);
}
@Override
public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) {
log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
PageData<Resource> resourcePageData = resourceDao.findResourcesByTenantIdAndResourceType(
tenantId,
ResourceType.LWM2M_MODEL, pageLink);
return resourcePageData.getData().stream()
.map(this::toLwM2mObject)
.sorted(getComparator(sortProperty, sortOrder))
.collect(Collectors.toList());
PageData<TbResource> resourcePageData = resourceDao.findResourcesByTenantIdAndResourceType(
tenantId,
ResourceType.LWM2M_MODEL, pageLink);
return resourcePageData.getData().stream()
.map(this::toLwM2mObject)
.sorted(getComparator(sortProperty, sortOrder))
.collect(Collectors.toList());
}
@Override
@ -107,9 +138,9 @@ public class BaseResourceService implements ResourceService {
String[] objectIds) {
log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
List<Resource> resources = resourceDao.findResourcesByTenantIdAndResourceType(tenantId, ResourceType.LWM2M_MODEL,
objectIds,
null);
List<TbResource> resources = resourceDao.findResourcesByTenantIdAndResourceType(tenantId, ResourceType.LWM2M_MODEL,
objectIds,
null);
return resources.stream()
.map(this::toLwM2mObject)
.sorted(getComparator(sortProperty, sortOrder))
@ -118,21 +149,21 @@ public class BaseResourceService implements ResourceService {
@Override
public void deleteResourcesByTenantId(TenantId tenantId) {
log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId);
log.trace("Executing deleteResourcesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
resourceDao.removeAllByTenantId(tenantId);
tenantResourcesRemover.removeEntities(tenantId, tenantId);
}
protected void validate(Resource resource) {
protected void validate(TbResource resource) {
if (resource == null) {
throw new DataValidationException("Resource should be specified!");
}
if (resource.getValue() == null) {
if (resource.getData() == null) {
throw new DataValidationException("Resource value should be specified!");
}
validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceId());
validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey());
if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && this.toLwM2mObject(resource) == null) {
throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getTextSearch()));
throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
}
}
@ -146,18 +177,18 @@ public class BaseResourceService implements ResourceService {
validateId(tenantId, "Incorrect tenantId ");
}
private LwM2mObject toLwM2mObject(Resource resource) {
private LwM2mObject toLwM2mObject(TbResource resource) {
try {
DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
List<ObjectModel> objectModels =
ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getValue())), resource.getTextSearch());
ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
if (objectModels.size() == 0) {
return null;
} else {
ObjectModel obj = objectModels.get(0);
LwM2mObject lwM2mObject = new LwM2mObject();
lwM2mObject.setId(obj.id);
lwM2mObject.setKeyId(resource.getResourceId());
lwM2mObject.setKeyId(resource.getResourceKey());
lwM2mObject.setName(obj.name);
lwM2mObject.setMultiple(obj.multiple);
lwM2mObject.setMandatory(obj.mandatory);
@ -170,12 +201,12 @@ public class BaseResourceService implements ResourceService {
resources.add(lwM2mResource);
}
});
instance.setResources(resources.stream().toArray(LwM2mResource[]::new));
instance.setResources(resources.toArray(LwM2mResource[]::new));
lwM2mObject.setInstances(new LwM2mInstance[]{instance});
return lwM2mObject;
}
} catch (IOException | InvalidDDFFileException e) {
log.error("Could not parse the XML of objectModel with name [{}]", resource.getTextSearch(), e);
log.error("Could not parse the XML of objectModel with name [{}]", resource.getSearchText(), e);
return null;
}
}
@ -190,4 +221,17 @@ public class BaseResourceService implements ResourceService {
return "DESC".equals(sortOrder) ? comparator.reversed() : comparator;
}
private PaginatedRemover<TenantId, TbResource> tenantResourcesRemover =
new PaginatedRemover<>() {
@Override
protected PageData<TbResource> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return resourceDao.findAllByTenantId(id, pageLink);
}
@Override
protected void removeEntity(TenantId tenantId, TbResource entity) {
deleteResource(tenantId, new TbResourceId(entity.getUuidId()));
}
};
}

47
dao/src/main/java/org/thingsboard/server/dao/resource/ResourceDao.java

@ -1,47 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.resource;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import java.util.List;
public interface ResourceDao {
Resource saveResource(Resource resource);
Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink);
PageData<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
ResourceType resourceType,
PageLink pageLink);
List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType);
List<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
ResourceType resourceType,
String[] objectIds,
String searchText);
void removeAllByTenantId(TenantId tenantId);
}

43
dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import java.util.List;
public interface TbResourceDao extends Dao<TbResource> {
TbResource saveResource(TbResource resource);
TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
PageData<TbResource> findAllByTenantId(TenantId tenantId, PageLink pageLink);
PageData<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
ResourceType resourceType,
PageLink pageLink);
List<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
ResourceType resourceType,
String[] objectIds,
String searchText);
}

29
dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceInfoDao.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.resource;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.Dao;
import java.util.UUID;
public interface TbResourceInfoDao extends Dao<TbResourceInfo> {
PageData<TbResourceInfo> findTbResourcesByTenantId(UUID tenantId, PageLink pageLink);
}

64
dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceDaoImpl.java → dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java

@ -16,72 +16,64 @@
package org.thingsboard.server.dao.sql.resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
import org.thingsboard.server.dao.model.sql.ResourceEntity;
import org.thingsboard.server.dao.resource.ResourceDao;
import org.thingsboard.server.dao.model.sql.TbResourceEntity;
import org.thingsboard.server.dao.resource.TbResourceDao;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@Slf4j
@Component
public class ResourceDaoImpl implements ResourceDao {
public class JpaTbResourceDao extends JpaAbstractSearchTextDao<TbResourceEntity, TbResource> implements TbResourceDao {
private final ResourceRepository resourceRepository;
private final TbResourceRepository resourceRepository;
public ResourceDaoImpl(ResourceRepository resourceRepository) {
public JpaTbResourceDao(TbResourceRepository resourceRepository) {
this.resourceRepository = resourceRepository;
}
@Override
@Transactional
public Resource saveResource(Resource resource) {
return DaoUtil.getData(resourceRepository.save(new ResourceEntity(resource)));
protected Class<TbResourceEntity> getEntityClass() {
return TbResourceEntity.class;
}
@Override
public Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
ResourceCompositeKey key = new ResourceCompositeKey();
key.setTenantId(tenantId.getId());
key.setResourceType(resourceType.name());
key.setResourceId(resourceId);
return DaoUtil.getData(resourceRepository.findById(key));
protected CrudRepository<TbResourceEntity, UUID> getCrudRepository() {
return resourceRepository;
}
@Override
@Transactional
public void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
ResourceCompositeKey key = new ResourceCompositeKey();
key.setTenantId(tenantId.getId());
key.setResourceType(resourceType.name());
key.setResourceId(resourceId);
resourceRepository.deleteById(key);
public TbResource saveResource(TbResource resource) {
return DaoUtil.getData(resourceRepository.save(new TbResourceEntity(resource)));
}
@Override
public PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {
return DaoUtil.getData(resourceRepository.findByTenantIdAndResourceTypeAndResourceKey(tenantId.getId(), resourceType.name(), resourceKey));
}
@Override
public List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType) {
return DaoUtil.convertDataList(resourceRepository.findAllByTenantIdAndResourceType(tenantId.getId(), resourceType.name()));
public PageData<TbResource> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
ResourceType resourceType,
PageLink pageLink) {
public PageData<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId,
ResourceType resourceType,
PageLink pageLink) {
return DaoUtil.toPageData(resourceRepository.findResourcesPage(
tenantId.getId(),
TenantId.SYS_TENANT_ID.getId(),
@ -92,9 +84,9 @@ public class ResourceDaoImpl implements ResourceDao {
}
@Override
public List<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType,
String[] objectIds,
String searchText) {
public List<TbResource> findResourcesByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType,
String[] objectIds,
String searchText) {
return objectIds == null ?
DaoUtil.convertDataList(resourceRepository.findResources(
tenantId.getId(),
@ -107,8 +99,4 @@ public class ResourceDaoImpl implements ResourceDao {
resourceType.name(), objectIds));
}
@Override
public void removeAllByTenantId(TenantId tenantId) {
resourceRepository.removeAllByTenantId(tenantId.getId());
}
}

59
dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceInfoDao.java

@ -0,0 +1,59 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.TbResourceInfo;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.TbResourceInfoEntity;
import org.thingsboard.server.dao.resource.TbResourceInfoDao;
import org.thingsboard.server.dao.sql.JpaAbstractSearchTextDao;
import java.util.Objects;
import java.util.UUID;
@Slf4j
@Component
public class JpaTbResourceInfoDao extends JpaAbstractSearchTextDao<TbResourceInfoEntity, TbResourceInfo> implements TbResourceInfoDao {
@Autowired
private TbResourceInfoRepository resourceInfoRepository;
@Override
protected Class<TbResourceInfoEntity> getEntityClass() {
return TbResourceInfoEntity.class;
}
@Override
protected CrudRepository<TbResourceInfoEntity, UUID> getCrudRepository() {
return resourceInfoRepository;
}
@Override
public PageData<TbResourceInfo> findTbResourcesByTenantId(UUID tenantId, PageLink pageLink) {
return DaoUtil.toPageData(resourceInfoRepository
.findByTenantId(
tenantId,
TenantId.NULL_UUID,
Objects.toString(pageLink.getTextSearch(), ""),
DaoUtil.toPageable(pageLink))); }
}

42
dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceInfoRepository.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.dao.model.sql.TbResourceInfoEntity;
import java.util.UUID;
public interface TbResourceInfoRepository extends CrudRepository<TbResourceInfoEntity, UUID> {
@Query("SELECT tr FROM TbResourceInfoEntity tr WHERE tr.tenantId = :tenantId " +
"AND LOWER(tr.searchText) LIKE LOWER(CONCAT(:searchText, '%'))" +
"AND (tr.tenantId = :tenantId " +
"OR (tr.tenantId = :systemAdminId " +
"AND NOT EXISTS " +
"(SELECT sr FROM TbResourceEntity sr " +
"WHERE sr.tenantId = :tenantId " +
"AND tr.resourceType = sr.resourceType " +
"AND tr.resourceKey = sr.resourceKey)))")
Page<TbResourceInfoEntity> findByTenantId(@Param("tenantId") UUID tenantId,
@Param("systemAdminId") UUID sysadminId,
@Param("searchText") String searchText,
Pageable pageable);
}

52
dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceRepository.java → dao/src/main/java/org/thingsboard/server/dao/sql/resource/TbResourceRepository.java

@ -20,65 +20,63 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
import org.thingsboard.server.dao.model.sql.ResourceEntity;
import org.thingsboard.server.dao.model.sql.TbResourceEntity;
import java.util.List;
import java.util.UUID;
public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> {
public interface TbResourceRepository extends CrudRepository<TbResourceEntity, UUID> {
TbResourceEntity findByTenantIdAndResourceTypeAndResourceKey(UUID tenantId, String resourceType, String resourceKey);
Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable);
Page<TbResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable);
@Query("SELECT tr FROM ResourceEntity tr " +
@Query("SELECT tr FROM TbResourceEntity tr " +
"WHERE tr.resourceType = :resourceType " +
"AND LOWER(tr.textSearch) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"AND LOWER(tr.searchText) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"AND (tr.tenantId = :tenantId " +
"OR (tr.tenantId = :systemAdminId " +
"AND NOT EXISTS " +
"(SELECT sr FROM ResourceEntity sr " +
"(SELECT sr FROM TbResourceEntity sr " +
"WHERE sr.tenantId = :tenantId " +
"AND sr.resourceType = :resourceType " +
"AND tr.resourceId = sr.resourceId)))")
Page<ResourceEntity> findResourcesPage(
"AND tr.resourceKey = sr.resourceKey)))")
Page<TbResourceEntity> findResourcesPage(
@Param("tenantId") UUID tenantId,
@Param("systemAdminId") UUID sysAdminId,
@Param("resourceType") String resourceType,
@Param("searchText") String search,
Pageable pageable);
List<ResourceEntity> findAllByTenantIdAndResourceType(UUID tenantId, String resourceType);
void removeAllByTenantId(UUID tenantId);
@Query("SELECT tr FROM ResourceEntity tr " +
@Query("SELECT tr FROM TbResourceEntity tr " +
"WHERE tr.resourceType = :resourceType " +
"AND LOWER(tr.textSearch) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"AND LOWER(tr.searchText) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"AND (tr.tenantId = :tenantId " +
"OR (tr.tenantId = :systemAdminId " +
"AND NOT EXISTS " +
"(SELECT sr FROM ResourceEntity sr " +
"(SELECT sr FROM TbResourceEntity sr " +
"WHERE sr.tenantId = :tenantId " +
"AND sr.resourceType = :resourceType " +
"AND tr.resourceId = sr.resourceId)))")
List<ResourceEntity> findResources(@Param("tenantId") UUID tenantId,
@Param("systemAdminId") UUID sysAdminId,
@Param("resourceType") String resourceType,
@Param("searchText") String search);
"AND tr.resourceKey = sr.resourceKey)))")
List<TbResourceEntity> findResources(@Param("tenantId") UUID tenantId,
@Param("systemAdminId") UUID sysAdminId,
@Param("resourceType") String resourceType,
@Param("searchText") String search);
@Query("SELECT tr FROM ResourceEntity tr " +
@Query("SELECT tr FROM TbResourceEntity tr " +
"WHERE tr.resourceType = :resourceType " +
"AND tr.resourceId in (:resourceIds) " +
"AND tr.resourceKey in (:resourceIds) " +
"AND (tr.tenantId = :tenantId " +
"OR (tr.tenantId = :systemAdminId " +
"AND NOT EXISTS " +
"(SELECT sr FROM ResourceEntity sr " +
"(SELECT sr FROM TbResourceEntity sr " +
"WHERE sr.tenantId = :tenantId " +
"AND sr.resourceType = :resourceType " +
"AND tr.resourceId = sr.resourceId)))")
List<ResourceEntity> findResourcesByIds(@Param("tenantId") UUID tenantId,
@Param("systemAdminId") UUID sysAdminId,
@Param("resourceType") String resourceType,
@Param("resourceIds") String[] objectIds);
"AND tr.resourceKey = sr.resourceKey)))")
List<TbResourceEntity> findResourcesByIds(@Param("tenantId") UUID tenantId,
@Param("systemAdminId") UUID sysAdminId,
@Param("resourceType") String resourceType,
@Param("resourceIds") String[] objectIds);
}

4
dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java

@ -35,7 +35,7 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entityview.EntityViewService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.dao.resource.TbResourceService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
@ -90,7 +90,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
private RuleChainService ruleChainService;
@Autowired
private ResourceService resourceService;
private TbResourceService resourceService;
@Override
public Tenant findTenantById(TenantId tenantId) {

11
dao/src/main/resources/sql/schema-entities-hsql.sql

@ -426,10 +426,13 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
);
CREATE TABLE IF NOT EXISTS resource (
id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY,
created_time bigint NOT NULL,
tenant_id uuid NOT NULL,
title varchar(255) NOT NULL,
resource_type varchar(32) NOT NULL,
resource_id varchar(255) NOT NULL,
text_search varchar(255),
resource_value varchar,
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)
resource_key varchar(255) NOT NULL,
search_text varchar(255),
data varchar,
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
);

11
dao/src/main/resources/sql/schema-entities.sql

@ -452,12 +452,15 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
);
CREATE TABLE IF NOT EXISTS resource (
id uuid NOT NULL CONSTRAINT resource_pkey PRIMARY KEY,
created_time bigint NOT NULL,
tenant_id uuid NOT NULL,
title varchar(255) NOT NULL,
resource_type varchar(32) NOT NULL,
resource_id varchar(255) NOT NULL,
text_search varchar(255),
resource_value varchar,
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)
resource_key varchar(255) NOT NULL,
search_text varchar(255),
data varchar,
CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_key)
);
CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint)

Loading…
Cancel
Save