committed by
GitHub
361 changed files with 15410 additions and 987 deletions
@ -0,0 +1,117 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.edqs; |
|||
|
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
import jakarta.annotation.PostConstruct; |
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.edqs.query.EdqsRequest; |
|||
import org.thingsboard.server.common.data.edqs.query.EdqsResponse; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.edqs.EdqsApiService; |
|||
import org.thingsboard.server.edqs.state.EdqsPartitionService; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.FromEdqsMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdqsMsg; |
|||
import org.thingsboard.server.queue.TbQueueRequestTemplate; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
import org.thingsboard.server.queue.provider.EdqsClientQueueFactory; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@ConditionalOnExpression("'${queue.edqs.api.supported:true}' == 'true' && ('${service.type:null}' == 'monolith' || '${service.type:null}' == 'tb-core')") |
|||
public class DefaultEdqsApiService implements EdqsApiService { |
|||
|
|||
private final EdqsPartitionService edqsPartitionService; |
|||
private final EdqsClientQueueFactory queueFactory; |
|||
private TbQueueRequestTemplate<TbProtoQueueMsg<ToEdqsMsg>, TbProtoQueueMsg<FromEdqsMsg>> requestTemplate; |
|||
|
|||
@Value("${queue.edqs.api.auto_enable:true}") |
|||
private boolean autoEnable; |
|||
|
|||
private Boolean apiEnabled = null; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
requestTemplate = queueFactory.createEdqsRequestTemplate(); |
|||
requestTemplate.init(); |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<EdqsResponse> processRequest(TenantId tenantId, CustomerId customerId, EdqsRequest request) { |
|||
var requestMsg = ToEdqsMsg.newBuilder() |
|||
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) |
|||
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) |
|||
.setTs(System.currentTimeMillis()) |
|||
.setRequestMsg(TransportProtos.EdqsRequestMsg.newBuilder() |
|||
.setValue(JacksonUtil.toString(request)) |
|||
.build()); |
|||
if (customerId != null && !customerId.isNullUid()) { |
|||
requestMsg.setCustomerIdMSB(customerId.getId().getMostSignificantBits()); |
|||
requestMsg.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); |
|||
} |
|||
|
|||
Integer partition = edqsPartitionService.resolvePartition(tenantId); |
|||
ListenableFuture<TbProtoQueueMsg<FromEdqsMsg>> resultFuture = requestTemplate.send(new TbProtoQueueMsg<>(UUID.randomUUID(), requestMsg.build()), partition); |
|||
return Futures.transform(resultFuture, msg -> { |
|||
TransportProtos.EdqsResponseMsg responseMsg = msg.getValue().getResponseMsg(); |
|||
return JacksonUtil.fromString(responseMsg.getValue(), EdqsResponse.class); |
|||
}, MoreExecutors.directExecutor()); |
|||
} |
|||
|
|||
@Override |
|||
public boolean isEnabled() { |
|||
return Boolean.TRUE.equals(apiEnabled); |
|||
} |
|||
|
|||
@Override |
|||
public void setEnabled(boolean enabled) { |
|||
if (enabled) { |
|||
log.info("Enabling EDQS API"); |
|||
} else { |
|||
log.info("Disabling EDQS API"); |
|||
} |
|||
apiEnabled = enabled; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isSupported() { |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isAutoEnable() { |
|||
return autoEnable; |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void stop() { |
|||
requestTemplate.stop(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,298 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.edqs; |
|||
|
|||
import com.google.protobuf.ByteString; |
|||
import jakarta.annotation.PostConstruct; |
|||
import jakarta.annotation.PreDestroy; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.SneakyThrows; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.context.annotation.Lazy; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.common.util.ThingsBoardExecutors; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.edqs.EdqsEventType; |
|||
import org.thingsboard.server.common.data.edqs.EdqsObject; |
|||
import org.thingsboard.server.common.data.edqs.EdqsSyncRequest; |
|||
import org.thingsboard.server.common.data.edqs.Entity; |
|||
import org.thingsboard.server.common.data.edqs.ToCoreEdqsMsg; |
|||
import org.thingsboard.server.common.data.edqs.ToCoreEdqsRequest; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
|||
import org.thingsboard.server.common.data.kv.JsonDataEntry; |
|||
import org.thingsboard.server.common.data.kv.KvEntry; |
|||
import org.thingsboard.server.common.msg.edqs.EdqsApiService; |
|||
import org.thingsboard.server.common.msg.edqs.EdqsService; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.dao.attributes.AttributesService; |
|||
import org.thingsboard.server.edqs.processor.EdqsProducer; |
|||
import org.thingsboard.server.edqs.state.EdqsPartitionService; |
|||
import org.thingsboard.server.edqs.util.EdqsConverter; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.EdqsEventMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdqsCoreServiceMsg; |
|||
import org.thingsboard.server.gen.transport.TransportProtos.ToEdqsMsg; |
|||
import org.thingsboard.server.queue.discovery.HashPartitionService; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.discovery.TopicService; |
|||
import org.thingsboard.server.queue.edqs.EdqsQueue; |
|||
import org.thingsboard.server.queue.environment.DistributedLock; |
|||
import org.thingsboard.server.queue.environment.DistributedLockService; |
|||
import org.thingsboard.server.queue.provider.EdqsClientQueueFactory; |
|||
import org.thingsboard.server.queue.util.AfterStartUp; |
|||
|
|||
import java.util.concurrent.ExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
@ConditionalOnProperty(value = "queue.edqs.sync.enabled", havingValue = "true") |
|||
public class DefaultEdqsService implements EdqsService { |
|||
|
|||
private final EdqsClientQueueFactory queueFactory; |
|||
private final EdqsConverter edqsConverter; |
|||
private final EdqsSyncService edqsSyncService; |
|||
private final EdqsApiService edqsApiService; |
|||
private final DistributedLockService distributedLockService; |
|||
private final AttributesService attributesService; |
|||
private final EdqsPartitionService edqsPartitionService; |
|||
private final TopicService topicService; |
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
@Autowired @Lazy |
|||
private TbClusterService clusterService; |
|||
@Autowired @Lazy |
|||
private HashPartitionService hashPartitionService; |
|||
|
|||
private EdqsProducer eventsProducer; |
|||
private ExecutorService executor; |
|||
private DistributedLock syncLock; |
|||
|
|||
@PostConstruct |
|||
private void init() { |
|||
executor = ThingsBoardExecutors.newWorkStealingPool(12, getClass()); |
|||
eventsProducer = EdqsProducer.builder() |
|||
.queue(EdqsQueue.EVENTS) |
|||
.partitionService(edqsPartitionService) |
|||
.topicService(topicService) |
|||
.producer(queueFactory.createEdqsMsgProducer(EdqsQueue.EVENTS)) |
|||
.build(); |
|||
syncLock = distributedLockService.getLock("edqs_sync"); |
|||
} |
|||
|
|||
@AfterStartUp(order = AfterStartUp.REGULAR_SERVICE) |
|||
public void onStartUp() { |
|||
if (!serviceInfoProvider.isService(ServiceType.TB_CORE)) { |
|||
return; |
|||
} |
|||
executor.submit(() -> { |
|||
try { |
|||
EdqsSyncState syncState = getSyncState(); |
|||
if (edqsSyncService.isSyncNeeded() || syncState == null || syncState.getStatus() != EdqsSyncStatus.FINISHED) { |
|||
if (hashPartitionService.isSystemPartitionMine(ServiceType.TB_CORE)) { |
|||
processSystemRequest(ToCoreEdqsRequest.builder() |
|||
.syncRequest(new EdqsSyncRequest()) |
|||
.build()); |
|||
} |
|||
} else if (edqsApiService.isSupported() && edqsApiService.isAutoEnable()) { |
|||
// only if topic/RocksDB is not empty and sync is finished
|
|||
edqsApiService.setEnabled(true); |
|||
} |
|||
} catch (Throwable e) { |
|||
log.error("Failed to start EDQS service", e); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
public void processSystemRequest(ToCoreEdqsRequest request) { |
|||
log.info("Processing system request {}", request); |
|||
if (request.getSyncRequest() != null) { |
|||
saveSyncState(EdqsSyncStatus.REQUESTED); |
|||
} |
|||
broadcast(request.toInternalMsg()); |
|||
} |
|||
|
|||
@Override |
|||
public void processSystemMsg(ToCoreEdqsMsg msg) { |
|||
executor.submit(() -> { |
|||
log.info("Processing system msg {}", msg); |
|||
try { |
|||
if (msg.getApiEnabled() != null) { |
|||
edqsApiService.setEnabled(msg.getApiEnabled()); |
|||
} |
|||
|
|||
if (msg.getSyncRequest() != null) { |
|||
syncLock.lock(); |
|||
try { |
|||
EdqsSyncState syncState = getSyncState(); |
|||
if (syncState != null && syncState.getStatus() == EdqsSyncStatus.FINISHED) { |
|||
log.info("EDQS sync is already finished"); |
|||
return; |
|||
} |
|||
|
|||
saveSyncState(EdqsSyncStatus.STARTED); |
|||
edqsSyncService.sync(); |
|||
saveSyncState(EdqsSyncStatus.FINISHED); |
|||
|
|||
if (edqsApiService.isSupported()) |
|||
if (edqsApiService.isAutoEnable()) { |
|||
log.info("EDQS sync is finished, auto-enabling API"); |
|||
broadcast(ToCoreEdqsMsg.builder() |
|||
.apiEnabled(Boolean.TRUE) |
|||
.build()); |
|||
} else { |
|||
log.info("EDQS sync is finished, but leaving API disabled"); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("Failed to complete sync", e); |
|||
saveSyncState(EdqsSyncStatus.FAILED); |
|||
} finally { |
|||
syncLock.unlock(); |
|||
} |
|||
} |
|||
} catch (Throwable e) { |
|||
log.error("Failed to process msg {}", msg, e); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@Override |
|||
public void onUpdate(TenantId tenantId, EntityId entityId, Object entity) { |
|||
EntityType entityType = entityId.getEntityType(); |
|||
ObjectType objectType = ObjectType.fromEntityType(entityType); |
|||
if (!isEdqsType(tenantId, objectType)) { |
|||
log.trace("[{}][{}] Ignoring update event, type {} not supported", tenantId, entityId, entityType); |
|||
return; |
|||
} |
|||
onUpdate(tenantId, objectType, edqsConverter.toEntity(entityType, entity)); |
|||
} |
|||
|
|||
@Override |
|||
public void onUpdate(TenantId tenantId, ObjectType objectType, EdqsObject object) { |
|||
processEvent(tenantId, objectType, EdqsEventType.UPDATED, object); |
|||
} |
|||
|
|||
@Override |
|||
public void onDelete(TenantId tenantId, EntityId entityId) { |
|||
EntityType entityType = entityId.getEntityType(); |
|||
ObjectType objectType = ObjectType.fromEntityType(entityType); |
|||
if (!isEdqsType(tenantId, objectType)) { |
|||
log.trace("[{}][{}] Ignoring deletion event, type {} not supported", tenantId, entityId, entityType); |
|||
return; |
|||
} |
|||
onDelete(tenantId, objectType, new Entity(entityType, entityId.getId(), Long.MAX_VALUE)); |
|||
} |
|||
|
|||
@Override |
|||
public void onDelete(TenantId tenantId, ObjectType objectType, EdqsObject object) { |
|||
processEvent(tenantId, objectType, EdqsEventType.DELETED, object); |
|||
} |
|||
|
|||
protected void processEvent(TenantId tenantId, ObjectType objectType, EdqsEventType eventType, EdqsObject object) { |
|||
executor.submit(() -> { |
|||
try { |
|||
String key = object.key(); |
|||
Long version = object.version(); |
|||
EdqsEventMsg.Builder eventMsg = EdqsEventMsg.newBuilder() |
|||
.setKey(key) |
|||
.setObjectType(objectType.name()) |
|||
.setData(ByteString.copyFrom(edqsConverter.serialize(objectType, object))) |
|||
.setEventType(eventType.name()); |
|||
if (version != null) { |
|||
eventMsg.setVersion(version); |
|||
} |
|||
eventsProducer.send(tenantId, objectType, key, ToEdqsMsg.newBuilder() |
|||
.setTenantIdMSB(tenantId.getId().getMostSignificantBits()) |
|||
.setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) |
|||
.setTs(System.currentTimeMillis()) |
|||
.setEventMsg(eventMsg) |
|||
.build()); |
|||
} catch (Throwable e) { |
|||
log.error("[{}] Failed to push {} event for {} {}", tenantId, eventType, objectType, object, e); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private boolean isEdqsType(TenantId tenantId, ObjectType objectType) { |
|||
if (objectType == null) { |
|||
return false; |
|||
} |
|||
if (!tenantId.isSysTenantId()) { |
|||
return ObjectType.edqsTypes.contains(objectType); |
|||
} else { |
|||
return ObjectType.edqsSystemTypes.contains(objectType); |
|||
} |
|||
} |
|||
|
|||
private void broadcast(ToCoreEdqsMsg msg) { |
|||
clusterService.broadcastToCore(ToCoreNotificationMsg.newBuilder() |
|||
.setToEdqsCoreServiceMsg(ToEdqsCoreServiceMsg.newBuilder() |
|||
.setValue(ByteString.copyFrom(JacksonUtil.writeValueAsBytes(msg)))) |
|||
.build()); |
|||
} |
|||
|
|||
@SneakyThrows |
|||
private EdqsSyncState getSyncState() { |
|||
EdqsSyncState state = attributesService.find(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID, AttributeScope.SERVER_SCOPE, "edqsSyncState").get(30, TimeUnit.SECONDS) |
|||
.flatMap(KvEntry::getJsonValue) |
|||
.map(value -> JacksonUtil.fromString(value, EdqsSyncState.class)) |
|||
.orElse(null); |
|||
log.info("EDQS sync state: {}", state); |
|||
return state; |
|||
} |
|||
|
|||
@SneakyThrows |
|||
private void saveSyncState(EdqsSyncStatus status) { |
|||
EdqsSyncState state = new EdqsSyncState(status); |
|||
log.info("New EDQS sync state: {}", state); |
|||
attributesService.save(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID, AttributeScope.SERVER_SCOPE, new BaseAttributeKvEntry( |
|||
new JsonDataEntry("edqsSyncState", JacksonUtil.toString(state)), |
|||
System.currentTimeMillis())).get(30, TimeUnit.SECONDS); |
|||
} |
|||
|
|||
@PreDestroy |
|||
private void stop() { |
|||
executor.shutdown(); |
|||
eventsProducer.stop(); |
|||
} |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
private static class EdqsSyncState { |
|||
private EdqsSyncStatus status; |
|||
} |
|||
|
|||
private enum EdqsSyncStatus { |
|||
REQUESTED, |
|||
STARTED, |
|||
FINISHED, |
|||
FAILED |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.edqs; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.event.TransactionalEventListener; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.msg.edqs.EdqsService; |
|||
import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; |
|||
import org.thingsboard.server.dao.eventsourcing.RelationActionEvent; |
|||
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; |
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@ConditionalOnProperty(value = "queue.edqs.sync.enabled", havingValue = "true") |
|||
public class EdqsListener { |
|||
|
|||
private final EdqsService edqsService; |
|||
|
|||
@TransactionalEventListener(fallbackExecution = true) |
|||
public void onUpdate(SaveEntityEvent<?> event) { |
|||
if (event.getEntityId() == null || event.getEntity() == null) { |
|||
return; |
|||
} |
|||
edqsService.onUpdate(event.getTenantId(), event.getEntityId(), event.getEntity()); |
|||
} |
|||
|
|||
@TransactionalEventListener(fallbackExecution = true) |
|||
public void onDelete(DeleteEntityEvent<?> event) { |
|||
if (event.getEntityId() == null) { |
|||
return; |
|||
} |
|||
edqsService.onDelete(event.getTenantId(), event.getEntityId()); |
|||
} |
|||
|
|||
@TransactionalEventListener(fallbackExecution = true) |
|||
public void handleEvent(RelationActionEvent relationEvent) { |
|||
if (relationEvent.getActionType() == ActionType.RELATION_ADD_OR_UPDATE) { |
|||
edqsService.onUpdate(relationEvent.getTenantId(), ObjectType.RELATION, relationEvent.getRelation()); |
|||
} else if (relationEvent.getActionType() == ActionType.RELATION_DELETED) { |
|||
edqsService.onDelete(relationEvent.getTenantId(), ObjectType.RELATION, relationEvent.getRelation()); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,284 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.edqs; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Lazy; |
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.edqs.AttributeKv; |
|||
import org.thingsboard.server.common.data.edqs.EdqsEventType; |
|||
import org.thingsboard.server.common.data.edqs.EdqsObject; |
|||
import org.thingsboard.server.common.data.edqs.Entity; |
|||
import org.thingsboard.server.common.data.edqs.LatestTsKv; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityFields; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageDataIterable; |
|||
import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
|||
import org.thingsboard.server.dao.Dao; |
|||
import org.thingsboard.server.dao.attributes.AttributesDao; |
|||
import org.thingsboard.server.dao.dictionary.KeyDictionaryDao; |
|||
import org.thingsboard.server.dao.entity.EntityDaoRegistry; |
|||
import org.thingsboard.server.dao.model.sql.AttributeKvEntity; |
|||
import org.thingsboard.server.dao.model.sql.RelationEntity; |
|||
import org.thingsboard.server.dao.model.sqlts.dictionary.KeyDictionaryEntry; |
|||
import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity; |
|||
import org.thingsboard.server.dao.sql.relation.RelationRepository; |
|||
import org.thingsboard.server.dao.sqlts.latest.TsKvLatestRepository; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
|
|||
import static org.thingsboard.server.common.data.ObjectType.ATTRIBUTE_KV; |
|||
import static org.thingsboard.server.common.data.ObjectType.LATEST_TS_KV; |
|||
import static org.thingsboard.server.common.data.ObjectType.RELATION; |
|||
import static org.thingsboard.server.common.data.ObjectType.edqsTenantTypes; |
|||
|
|||
@Slf4j |
|||
public abstract class EdqsSyncService { |
|||
|
|||
@Value("${queue.edqs.sync.entity_batch_size:10000}") |
|||
private int entityBatchSize; |
|||
@Value("${queue.edqs.sync.ts_batch_size:10000}") |
|||
private int tsBatchSize; |
|||
@Autowired |
|||
private EntityDaoRegistry entityDaoRegistry; |
|||
@Autowired |
|||
private AttributesDao attributesDao; |
|||
@Autowired |
|||
private KeyDictionaryDao keyDictionaryDao; |
|||
@Autowired |
|||
private RelationRepository relationRepository; |
|||
@Autowired |
|||
private TsKvLatestRepository tsKvLatestRepository; |
|||
@Autowired |
|||
@Lazy |
|||
private DefaultEdqsService edqsService; |
|||
|
|||
private final ConcurrentHashMap<UUID, EntityIdInfo> entityInfoMap = new ConcurrentHashMap<>(); |
|||
private final ConcurrentHashMap<Integer, String> keys = new ConcurrentHashMap<>(); |
|||
|
|||
private final Map<ObjectType, AtomicInteger> counters = new ConcurrentHashMap<>(); |
|||
|
|||
public abstract boolean isSyncNeeded(); |
|||
|
|||
public void sync() { |
|||
log.info("Synchronizing data to EDQS"); |
|||
long startTs = System.currentTimeMillis(); |
|||
counters.clear(); |
|||
|
|||
syncTenantEntities(); |
|||
syncRelations(); |
|||
loadKeyDictionary(); |
|||
syncAttributes(); |
|||
syncLatestTimeseries(); |
|||
|
|||
counters.clear(); |
|||
log.info("Finishing synchronizing data to EDQS in {} ms", (System.currentTimeMillis() - startTs)); |
|||
} |
|||
|
|||
private void process(TenantId tenantId, ObjectType type, EdqsObject object) { |
|||
AtomicInteger counter = counters.computeIfAbsent(type, t -> new AtomicInteger()); |
|||
if (counter.incrementAndGet() % 10000 == 0) { |
|||
log.info("Processed {} {} objects", counter.get(), type); |
|||
} |
|||
edqsService.processEvent(tenantId, type, EdqsEventType.UPDATED, object); |
|||
} |
|||
|
|||
private void syncTenantEntities() { |
|||
for (ObjectType type : edqsTenantTypes) { |
|||
log.info("Synchronizing {} entities to EDQS", type); |
|||
long ts = System.currentTimeMillis(); |
|||
EntityType entityType = type.toEntityType(); |
|||
Dao<?> dao = entityDaoRegistry.getDao(entityType); |
|||
UUID lastId = UUID.fromString("00000000-0000-0000-0000-000000000000"); |
|||
while (true) { |
|||
var batch = dao.findNextBatch(lastId, entityBatchSize); |
|||
if (batch.isEmpty()) { |
|||
break; |
|||
} |
|||
for (EntityFields entityFields : batch) { |
|||
TenantId tenantId = TenantId.fromUUID(entityFields.getTenantId()); |
|||
entityInfoMap.put(entityFields.getId(), new EntityIdInfo(entityType, tenantId)); |
|||
process(tenantId, type, new Entity(entityType, entityFields)); |
|||
} |
|||
EntityFields lastRecord = batch.get(batch.size() - 1); |
|||
lastId = lastRecord.getId(); |
|||
} |
|||
log.info("Finished synchronizing {} entities to EDQS in {} ms", type, (System.currentTimeMillis() - ts)); |
|||
} |
|||
} |
|||
|
|||
private void syncRelations() { |
|||
log.info("Synchronizing relations to EDQS"); |
|||
long ts = System.currentTimeMillis(); |
|||
UUID lastFromEntityId = UUID.fromString("00000000-0000-0000-0000-000000000000"); |
|||
String lastFromEntityType = ""; |
|||
String lastRelationTypeGroup = ""; |
|||
String lastRelationType = ""; |
|||
UUID lastToEntityId = UUID.fromString("00000000-0000-0000-0000-000000000000"); |
|||
String lastToEntityType = ""; |
|||
|
|||
while (true) { |
|||
List<RelationEntity> batch = relationRepository.findNextBatch(lastFromEntityId, lastFromEntityType, lastRelationTypeGroup, |
|||
lastRelationType, lastToEntityId, lastToEntityType, entityBatchSize); |
|||
if (batch.isEmpty()) { |
|||
break; |
|||
} |
|||
processRelationBatch(batch); |
|||
|
|||
RelationEntity lastRecord = batch.get(batch.size() - 1); |
|||
lastFromEntityId = lastRecord.getFromId(); |
|||
lastFromEntityType = lastRecord.getFromType(); |
|||
lastRelationTypeGroup = lastRecord.getRelationTypeGroup(); |
|||
lastRelationType = lastRecord.getRelationType(); |
|||
lastToEntityId = lastRecord.getToId(); |
|||
lastToEntityType = lastRecord.getToType(); |
|||
} |
|||
log.info("Finished synchronizing relations to EDQS in {} ms", (System.currentTimeMillis() - ts)); |
|||
} |
|||
|
|||
private void processRelationBatch(List<RelationEntity> relations) { |
|||
for (RelationEntity relation : relations) { |
|||
if (RelationTypeGroup.COMMON.name().equals(relation.getRelationTypeGroup())) { |
|||
EntityIdInfo entityIdInfo = entityInfoMap.get(relation.getFromId()); |
|||
if (entityIdInfo != null) { |
|||
process(entityIdInfo.tenantId(), RELATION, relation.toData()); |
|||
} else { |
|||
log.info("Relation from id not found: {} ", relation); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void loadKeyDictionary() { |
|||
log.info("Loading key dictionary"); |
|||
long ts = System.currentTimeMillis(); |
|||
var keyDictionaryEntries = new PageDataIterable<>(keyDictionaryDao::findAll, 10000); |
|||
for (KeyDictionaryEntry keyDictionaryEntry : keyDictionaryEntries) { |
|||
keys.put(keyDictionaryEntry.getKeyId(), keyDictionaryEntry.getKey()); |
|||
} |
|||
log.info("Finished loading key dictionary in {} ms", (System.currentTimeMillis() - ts)); |
|||
} |
|||
|
|||
private void syncAttributes() { |
|||
log.info("Synchronizing attributes to EDQS"); |
|||
long ts = System.currentTimeMillis(); |
|||
|
|||
UUID lastEntityId = UUID.fromString("00000000-0000-0000-0000-000000000000"); |
|||
int lastAttributeType = Integer.MIN_VALUE; |
|||
int lastAttributeKey = Integer.MIN_VALUE; |
|||
|
|||
while (true) { |
|||
List<AttributeKvEntity> batch = attributesDao.findNextBatch(lastEntityId, lastAttributeType, lastAttributeKey, tsBatchSize); |
|||
if (batch.isEmpty()) { |
|||
break; |
|||
} |
|||
processAttributeBatch(batch); |
|||
|
|||
AttributeKvEntity lastRecord = batch.get(batch.size() - 1); |
|||
lastEntityId = lastRecord.getId().getEntityId(); |
|||
lastAttributeType = lastRecord.getId().getAttributeType(); |
|||
lastAttributeKey = lastRecord.getId().getAttributeKey(); |
|||
} |
|||
log.info("Finished synchronizing attributes to EDQS in {} ms", (System.currentTimeMillis() - ts)); |
|||
} |
|||
|
|||
private void processAttributeBatch(List<AttributeKvEntity> batch) { |
|||
for (AttributeKvEntity attribute : batch) { |
|||
attribute.setStrKey(getStrKeyOrFetchFromDb(attribute.getId().getAttributeKey())); |
|||
UUID entityId = attribute.getId().getEntityId(); |
|||
EntityIdInfo entityIdInfo = entityInfoMap.get(entityId); |
|||
if (entityIdInfo == null) { |
|||
log.debug("Skipping attribute with entity UUID {} as it is not found in entityInfoMap", entityId); |
|||
continue; |
|||
} |
|||
AttributeKv attributeKv = new AttributeKv( |
|||
EntityIdFactory.getByTypeAndUuid(entityIdInfo.entityType(), entityId), |
|||
AttributeScope.valueOf(attribute.getId().getAttributeType()), |
|||
attribute.toData(), |
|||
attribute.getVersion()); |
|||
process(entityIdInfo.tenantId(), ATTRIBUTE_KV, attributeKv); |
|||
} |
|||
} |
|||
|
|||
private void syncLatestTimeseries() { |
|||
log.info("Synchronizing latest timeseries to EDQS"); |
|||
long ts = System.currentTimeMillis(); |
|||
UUID lastEntityId = UUID.fromString("00000000-0000-0000-0000-000000000000"); |
|||
int lastKey = Integer.MIN_VALUE; |
|||
|
|||
while (true) { |
|||
List<TsKvLatestEntity> batch = tsKvLatestRepository.findNextBatch(lastEntityId, lastKey, tsBatchSize); |
|||
if (batch.isEmpty()) { |
|||
break; |
|||
} |
|||
processTsKvLatestBatch(batch); |
|||
|
|||
TsKvLatestEntity lastRecord = batch.get(batch.size() - 1); |
|||
lastEntityId = lastRecord.getEntityId(); |
|||
lastKey = lastRecord.getKey(); |
|||
} |
|||
log.info("Finished synchronizing latest timeseries to EDQS in {} ms", (System.currentTimeMillis() - ts)); |
|||
} |
|||
|
|||
private void processTsKvLatestBatch(List<TsKvLatestEntity> tsKvLatestEntities) { |
|||
for (TsKvLatestEntity tsKvLatestEntity : tsKvLatestEntities) { |
|||
try { |
|||
String strKey = getStrKeyOrFetchFromDb(tsKvLatestEntity.getKey()); |
|||
if (strKey == null) { |
|||
log.debug("Skipping latest timeseries with key {} as it is not found in key dictionary", tsKvLatestEntity.getKey()); |
|||
continue; |
|||
} |
|||
tsKvLatestEntity.setStrKey(strKey); |
|||
UUID entityUuid = tsKvLatestEntity.getEntityId(); |
|||
EntityIdInfo entityIdInfo = entityInfoMap.get(entityUuid); |
|||
if (entityIdInfo != null) { |
|||
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityIdInfo.entityType(), entityUuid); |
|||
LatestTsKv latestTsKv = new LatestTsKv(entityId, tsKvLatestEntity.toData(), tsKvLatestEntity.getVersion()); |
|||
process(entityIdInfo.tenantId(), LATEST_TS_KV, latestTsKv); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("Failed to sync latest timeseries: {}", tsKvLatestEntity, e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private String getStrKeyOrFetchFromDb(int key) { |
|||
String strKey = keys.get(key); |
|||
if (strKey != null) { |
|||
return strKey; |
|||
} else { |
|||
strKey = keyDictionaryDao.getKey(key); |
|||
if (strKey != null) { |
|||
keys.put(key, strKey); |
|||
} |
|||
} |
|||
return strKey; |
|||
} |
|||
|
|||
public record EntityIdInfo(EntityType entityType, TenantId tenantId) { |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.edqs; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.queue.edqs.EdqsQueue; |
|||
import org.thingsboard.server.queue.kafka.TbKafkaAdmin; |
|||
import org.thingsboard.server.queue.kafka.TbKafkaSettings; |
|||
|
|||
import java.util.Collections; |
|||
|
|||
@Service |
|||
@ConditionalOnExpression("'${queue.edqs.sync.enabled:true}' == 'true' && '${queue.type:null}' == 'kafka'") |
|||
public class KafkaEdqsSyncService extends EdqsSyncService { |
|||
|
|||
private final boolean syncNeeded; |
|||
|
|||
public KafkaEdqsSyncService(TbKafkaSettings kafkaSettings) { |
|||
TbKafkaAdmin kafkaAdmin = new TbKafkaAdmin(kafkaSettings, Collections.emptyMap()); |
|||
this.syncNeeded = kafkaAdmin.isTopicEmpty(EdqsQueue.EVENTS.getTopic()); |
|||
} |
|||
|
|||
@Override |
|||
public boolean isSyncNeeded() { |
|||
return syncNeeded; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.edqs; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.edqs.util.EdqsRocksDb; |
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@ConditionalOnExpression("'${queue.edqs.sync.enabled:true}' == 'true' && '${queue.type:null}' == 'in-memory'") |
|||
public class LocalEdqsSyncService extends EdqsSyncService { |
|||
|
|||
private final EdqsRocksDb db; |
|||
|
|||
@Override |
|||
public boolean isSyncNeeded() { |
|||
return db.isNew(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.controller; |
|||
|
|||
import org.junit.Before; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.test.mock.mockito.MockBean; |
|||
import org.springframework.test.context.TestPropertySource; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.EntityCountQuery; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.common.data.query.EntityDataQuery; |
|||
import org.thingsboard.server.common.msg.edqs.EdqsApiService; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.edqs.state.EdqsStateService; |
|||
import org.thingsboard.server.edqs.util.EdqsRocksDb; |
|||
|
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.awaitility.Awaitility.await; |
|||
|
|||
@DaoSqlTest |
|||
@TestPropertySource(properties = { |
|||
// "queue.type=kafka", // uncomment to use Kafka
|
|||
// "queue.kafka.bootstrap.servers=10.7.1.254:9092",
|
|||
"queue.edqs.sync.enabled=true", |
|||
"queue.edqs.api.supported=true", |
|||
"queue.edqs.api.auto_enable=true", |
|||
"queue.edqs.mode=local" |
|||
}) |
|||
public class EdqsEntityQueryControllerTest extends EntityQueryControllerTest { |
|||
|
|||
@Autowired |
|||
private EdqsApiService edqsApiService; |
|||
|
|||
@Autowired |
|||
private EdqsStateService edqsStateService; |
|||
|
|||
@MockBean // so that we don't do backup for tests
|
|||
private EdqsRocksDb edqsRocksDb; |
|||
|
|||
@Before |
|||
public void before() { |
|||
await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> edqsApiService.isEnabled() && edqsStateService.isReady()); |
|||
} |
|||
|
|||
@Override |
|||
protected PageData<EntityData> findByQueryAndCheck(EntityDataQuery query, int expectedResultSize) { |
|||
return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> findByQuery(query), |
|||
result -> result.getTotalElements() == expectedResultSize); |
|||
} |
|||
|
|||
@Override |
|||
protected Long countByQueryAndCheck(EntityCountQuery query, long expectedResult) { |
|||
return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> countByQuery(query), |
|||
result -> result == expectedResult); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,128 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.service.entitiy; |
|||
|
|||
import com.google.common.collect.Lists; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.test.mock.mockito.MockBean; |
|||
import org.springframework.test.context.TestPropertySource; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.IdBased; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.EntityCountQuery; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.common.data.query.EntityDataQuery; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.common.data.query.RelationsQueryFilter; |
|||
import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
|||
import org.thingsboard.server.common.data.relation.RelationEntityTypeFilter; |
|||
import org.thingsboard.server.common.msg.edqs.EdqsApiService; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.edqs.util.EdqsRocksDb; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.stream.Collectors; |
|||
|
|||
import static org.awaitility.Awaitility.await; |
|||
|
|||
@DaoSqlTest |
|||
@TestPropertySource(properties = { |
|||
"queue.edqs.sync.enabled=true", |
|||
"queue.edqs.api.supported=true", |
|||
"queue.edqs.api.auto_enable=true", |
|||
"queue.edqs.mode=local" |
|||
}) |
|||
public class EdqsEntityServiceTest extends EntityServiceTest { |
|||
|
|||
@Autowired |
|||
private EdqsApiService edqsApiService; |
|||
|
|||
@MockBean |
|||
private EdqsRocksDb edqsRocksDb; |
|||
|
|||
@Before |
|||
public void beforeEach() { |
|||
await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> edqsApiService.isEnabled()); |
|||
} |
|||
|
|||
// sql implementation has a bug with data duplication, edqs implementation returns correct value
|
|||
@Override |
|||
@Test |
|||
public void testCountHierarchicalEntitiesByMultiRootQuery() throws InterruptedException { |
|||
List<Asset> buildings = new ArrayList<>(); |
|||
List<Asset> apartments = new ArrayList<>(); |
|||
Map<String, Map<UUID, String>> entityNameByTypeMap = new HashMap<>(); |
|||
Map<UUID, UUID> childParentRelationMap = new HashMap<>(); |
|||
createMultiRootHierarchy(buildings, apartments, entityNameByTypeMap, childParentRelationMap); |
|||
|
|||
RelationsQueryFilter filter = new RelationsQueryFilter(); |
|||
filter.setMultiRoot(true); |
|||
filter.setMultiRootEntitiesType(EntityType.ASSET); |
|||
filter.setMultiRootEntityIds(buildings.stream().map(IdBased::getId).map(d -> d.getId().toString()).collect(Collectors.toSet())); |
|||
filter.setDirection(EntitySearchDirection.FROM); |
|||
|
|||
EntityCountQuery countQuery = new EntityCountQuery(filter); |
|||
countByQueryAndCheck(countQuery, 63); |
|||
|
|||
filter.setFilters(Collections.singletonList(new RelationEntityTypeFilter("AptToHeat", Collections.singletonList(EntityType.DEVICE)))); |
|||
countByQueryAndCheck(countQuery, 27); |
|||
|
|||
filter.setMultiRootEntitiesType(EntityType.ASSET); |
|||
filter.setMultiRootEntityIds(apartments.stream().map(IdBased::getId).map(d -> d.getId().toString()).collect(Collectors.toSet())); |
|||
filter.setDirection(EntitySearchDirection.TO); |
|||
filter.setFilters(Lists.newArrayList( |
|||
new RelationEntityTypeFilter("buildingToApt", Collections.singletonList(EntityType.ASSET)), |
|||
new RelationEntityTypeFilter("AptToEnergy", Collections.singletonList(EntityType.DEVICE)))); |
|||
countByQueryAndCheck(countQuery, 3); |
|||
|
|||
deviceService.deleteDevicesByTenantId(tenantId); |
|||
assetService.deleteAssetsByTenantId(tenantId); |
|||
} |
|||
|
|||
@Override |
|||
protected PageData<EntityData> findByQueryAndCheck(CustomerId customerId, EntityDataQuery query, long expectedResultSize) { |
|||
return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> findByQuery(customerId, query), |
|||
result -> result.getTotalElements() == expectedResultSize); |
|||
} |
|||
|
|||
@Override |
|||
protected List<EntityData> findByQueryAndCheckTelemetry(EntityDataQuery query, EntityKeyType entityKeyType, String key, List<String> expectedTelemetries) { |
|||
return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> findEntitiesTelemetry(query, entityKeyType, key, expectedTelemetries), |
|||
loadedEntities -> loadedEntities.stream().map(entityData -> entityData.getLatest().get(entityKeyType).get(key).getValue()).toList().containsAll(expectedTelemetries)); |
|||
} |
|||
|
|||
@Override |
|||
protected long countByQueryAndCheck(EntityCountQuery countQuery, int expectedResult) { |
|||
return countByQueryAndCheck(new CustomerId(CustomerId.NULL_UUID), countQuery, expectedResult); |
|||
} |
|||
|
|||
@Override |
|||
protected long countByQueryAndCheck(CustomerId customerId, EntityCountQuery query, int expectedResult) { |
|||
return await().atMost(TIMEOUT, TimeUnit.SECONDS).until(() -> countByQuery(customerId, query), |
|||
result -> result == expectedResult); |
|||
} |
|||
|
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,89 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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 java.util.EnumSet; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public enum ObjectType { |
|||
TENANT, |
|||
TENANT_PROFILE, |
|||
CUSTOMER, |
|||
QUEUE, |
|||
RPC, |
|||
RULE_CHAIN, |
|||
OTA_PACKAGE, |
|||
RESOURCE, |
|||
EVENT, |
|||
RULE_NODE, |
|||
USER, |
|||
EDGE, |
|||
WIDGETS_BUNDLE, |
|||
WIDGET_TYPE, |
|||
DASHBOARD, |
|||
DEVICE_PROFILE, |
|||
DEVICE, |
|||
DEVICE_CREDENTIALS, |
|||
ASSET_PROFILE, |
|||
ASSET, |
|||
ENTITY_VIEW, |
|||
ALARM, |
|||
ENTITY_ALARM, |
|||
OAUTH2_CLIENT, |
|||
OAUTH2_DOMAIN, |
|||
OAUTH2_MOBILE, |
|||
USER_SETTINGS, |
|||
NOTIFICATION_TARGET, |
|||
NOTIFICATION_TEMPLATE, |
|||
NOTIFICATION_RULE, |
|||
ALARM_COMMENT, |
|||
API_USAGE_STATE, |
|||
QUEUE_STATS, |
|||
|
|||
AUDIT_LOG, |
|||
RELATION, |
|||
ATTRIBUTE_KV, |
|||
LATEST_TS_KV; |
|||
|
|||
public static final Set<ObjectType> edqsTenantTypes = EnumSet.of( |
|||
TENANT, CUSTOMER, DEVICE_PROFILE, DEVICE, ASSET_PROFILE, ASSET, EDGE, ENTITY_VIEW, USER, DASHBOARD, |
|||
RULE_CHAIN, WIDGET_TYPE, WIDGETS_BUNDLE, API_USAGE_STATE, QUEUE_STATS |
|||
); |
|||
public static final Set<ObjectType> edqsTypes = EnumSet.copyOf(edqsTenantTypes); |
|||
public static final Set<ObjectType> edqsSystemTypes = EnumSet.of(TENANT, USER, DASHBOARD, |
|||
API_USAGE_STATE, ATTRIBUTE_KV, LATEST_TS_KV); |
|||
public static final Set<ObjectType> unversionedTypes = EnumSet.of( |
|||
QUEUE_STATS // created once, never updated
|
|||
); |
|||
|
|||
static { |
|||
edqsTypes.addAll(List.of(RELATION, ATTRIBUTE_KV, LATEST_TS_KV)); |
|||
} |
|||
|
|||
public EntityType toEntityType() { |
|||
return EntityType.valueOf(name()); |
|||
} |
|||
|
|||
public static ObjectType fromEntityType(EntityType entityType) { |
|||
try { |
|||
return ObjectType.valueOf(entityType.name()); |
|||
} catch (Exception e) { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
import org.thingsboard.server.common.data.kv.KvEntry; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
@Builder |
|||
public class AttributeKv implements EdqsObject { |
|||
|
|||
private EntityId entityId; |
|||
private AttributeScope scope; |
|||
private String key; |
|||
private Long version; |
|||
|
|||
private DataPoint dataPoint; // optional (on deletion)
|
|||
|
|||
private Long lastUpdateTs; // only for serialization
|
|||
private KvEntry value; // only for serialization
|
|||
|
|||
public AttributeKv(EntityId entityId, AttributeScope scope, AttributeKvEntry attributeKvEntry, long version) { |
|||
this.entityId = entityId; |
|||
this.scope = scope; |
|||
this.key = attributeKvEntry.getKey(); |
|||
this.version = version; |
|||
this.lastUpdateTs = attributeKvEntry.getLastUpdateTs(); |
|||
this.value = attributeKvEntry; |
|||
} |
|||
|
|||
public AttributeKv(EntityId entityId, AttributeScope scope, String key, long version) { |
|||
this.entityId = entityId; |
|||
this.scope = scope; |
|||
this.key = key; |
|||
this.version = version; |
|||
} |
|||
|
|||
@Override |
|||
public String key() { |
|||
return "a_" + entityId + "_" + scope + "_" + key; |
|||
} |
|||
|
|||
@Override |
|||
public Long version() { |
|||
return version; |
|||
} |
|||
|
|||
@Override |
|||
public ObjectType type() { |
|||
return ObjectType.ATTRIBUTE_KV; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
|
|||
public interface DataPoint { |
|||
|
|||
String NOT_SUPPORTED = "Not supported!"; |
|||
|
|||
long getTs(); |
|||
|
|||
DataType getType(); |
|||
|
|||
String getStr(); |
|||
|
|||
long getLong(); |
|||
|
|||
double getDouble(); |
|||
|
|||
boolean getBool(); |
|||
|
|||
String getJson(); |
|||
|
|||
String valueToString(); |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@Builder |
|||
public class EdqsEvent { |
|||
|
|||
private final TenantId tenantId; |
|||
private final ObjectType objectType; |
|||
private final EdqsEventType eventType; |
|||
private final EdqsObject object; |
|||
|
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
public enum EdqsEventType { |
|||
UPDATED, |
|||
DELETED |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
|
|||
public interface EdqsObject { |
|||
|
|||
@JsonIgnore |
|||
String key(); |
|||
|
|||
@JsonIgnore |
|||
Long version(); |
|||
|
|||
@JsonIgnore |
|||
ObjectType type(); |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
@JsonIgnoreProperties |
|||
public class EdqsSyncRequest { |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityFields; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityIdFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
public class Entity implements EdqsObject { |
|||
|
|||
private EntityType type; |
|||
|
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) |
|||
private EntityFields fields; |
|||
|
|||
public Entity(EntityType type) { |
|||
this.type = type; |
|||
} |
|||
|
|||
public Entity(EntityType type, EntityFields fields) { |
|||
this.type = type; |
|||
this.fields = fields; |
|||
} |
|||
|
|||
public Entity(EntityType entityType, UUID id, long version) { |
|||
this.type = entityType; |
|||
this.fields = new EntityIdFields(id, version); |
|||
} |
|||
|
|||
@Override |
|||
public String key() { |
|||
return "e_" + fields.getId().toString(); |
|||
} |
|||
|
|||
@Override |
|||
public Long version() { |
|||
return fields.getVersion(); |
|||
} |
|||
|
|||
@Override |
|||
public ObjectType type() { |
|||
return ObjectType.fromEntityType(type); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.thingsboard.server.common.data.ObjectType; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.kv.KvEntry; |
|||
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
@Builder |
|||
public class LatestTsKv implements EdqsObject { |
|||
|
|||
private EntityId entityId; |
|||
private String key; |
|||
private Long version; |
|||
|
|||
private DataPoint dataPoint; // optional (on deletion)
|
|||
|
|||
private Long ts; // only for serialization
|
|||
private KvEntry value; // only for serialization
|
|||
|
|||
public LatestTsKv(EntityId entityId, TsKvEntry tsKvEntry, Long version) { |
|||
this.entityId = entityId; |
|||
this.key = tsKvEntry.getKey(); |
|||
this.ts = tsKvEntry.getTs(); |
|||
this.version = version != null ? version : 0L; |
|||
this.value = tsKvEntry; |
|||
} |
|||
|
|||
public LatestTsKv(EntityId entityId, String key, Long version) { |
|||
this.entityId = entityId; |
|||
this.key = key; |
|||
this.version = version != null ? version : 0L; |
|||
} |
|||
|
|||
public String key() { |
|||
return "l_" + entityId + "_" + key; |
|||
} |
|||
|
|||
@Override |
|||
public Long version() { |
|||
return version; |
|||
} |
|||
|
|||
@Override |
|||
public ObjectType type() { |
|||
return ObjectType.LATEST_TS_KV; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
@Builder |
|||
public class ToCoreEdqsMsg { |
|||
|
|||
private EdqsSyncRequest syncRequest; |
|||
private Boolean apiEnabled; |
|||
|
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@AllArgsConstructor |
|||
@Builder |
|||
public class ToCoreEdqsRequest { |
|||
|
|||
private EdqsSyncRequest syncRequest; |
|||
private Boolean apiEnabled; |
|||
|
|||
@JsonIgnore |
|||
public ToCoreEdqsMsg toInternalMsg() { |
|||
return new ToCoreEdqsMsg(syncRequest, apiEnabled); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.experimental.SuperBuilder; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@SuperBuilder |
|||
public class AbstractEntityFields implements EntityFields { |
|||
|
|||
private UUID id; |
|||
private long createdTime; |
|||
private UUID tenantId; |
|||
private UUID customerId; |
|||
private String name; |
|||
private Long version; |
|||
|
|||
public AbstractEntityFields(UUID id, long createdTime, UUID tenantId, UUID customerId, String name, Long version) { |
|||
this.id = id; |
|||
this.createdTime = createdTime; |
|||
this.tenantId = tenantId; |
|||
this.customerId = (customerId != null && customerId != CustomerId.NULL_UUID) ? customerId : null; |
|||
this.name = name; |
|||
this.version = version; |
|||
} |
|||
|
|||
public AbstractEntityFields() { |
|||
} |
|||
|
|||
public AbstractEntityFields(UUID id, long createdTime, UUID tenantId, String name, Long version) { |
|||
this(id, createdTime, tenantId, null, name, version); |
|||
} |
|||
|
|||
public AbstractEntityFields(UUID id, long createdTime, UUID tenantId, UUID customerId, Long version) { |
|||
this(id, createdTime, tenantId, customerId, null, version); |
|||
|
|||
} |
|||
|
|||
public AbstractEntityFields(UUID id, long createdTime, String name, Long version) { |
|||
this(id, createdTime, null, name, version); |
|||
} |
|||
|
|||
|
|||
public AbstractEntityFields(UUID id, long createdTime, UUID tenantId) { |
|||
this(id, createdTime, tenantId, null, null, null); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
import org.thingsboard.server.common.data.ApiUsageStateValue; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class ApiUsageStateFields extends AbstractEntityFields { |
|||
|
|||
private EntityId entityId; |
|||
private ApiUsageStateValue transportState; |
|||
private ApiUsageStateValue dbStorageState; |
|||
private ApiUsageStateValue reExecState; |
|||
private ApiUsageStateValue jsExecState; |
|||
private ApiUsageStateValue tbelExecState; |
|||
private ApiUsageStateValue emailExecState; |
|||
private ApiUsageStateValue smsExecState; |
|||
private ApiUsageStateValue alarmExecState; |
|||
|
|||
public ApiUsageStateFields(UUID id, long createdTime, UUID tenantId, UUID entityId, String entityType, ApiUsageStateValue transportState, ApiUsageStateValue dbStorageState, |
|||
ApiUsageStateValue reExecState, ApiUsageStateValue jsExecState, ApiUsageStateValue tbelExecState, |
|||
ApiUsageStateValue emailExecState, ApiUsageStateValue smsExecState, ApiUsageStateValue alarmExecState, |
|||
Long version) { |
|||
super(id, createdTime, tenantId, null, null, version); |
|||
this.entityId = (entityType != null && entityId != null) ? EntityIdFactory.getByTypeAndUuid(entityType, entityId) : null; |
|||
this.transportState = transportState; |
|||
this.dbStorageState = dbStorageState; |
|||
this.reExecState = reExecState; |
|||
this.jsExecState = jsExecState; |
|||
this.tbelExecState = tbelExecState; |
|||
this.emailExecState = emailExecState; |
|||
this.smsExecState = smsExecState; |
|||
this.alarmExecState = alarmExecState; |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class AssetFields extends AbstractEntityFields implements ProfileAwareFields { |
|||
|
|||
private String type; |
|||
private UUID assetProfileId; |
|||
private String label; |
|||
private String additionalInfo; |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public String getProfileName() { |
|||
return type; |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public UUID getProfileId() { |
|||
return assetProfileId; |
|||
} |
|||
|
|||
public AssetFields(UUID id, long createdTime, UUID tenantId, UUID customerId, String name, |
|||
Long version, String type, String label, UUID assetProfileId, JsonNode additionalInfo) { |
|||
super(id, createdTime, tenantId, customerId, name, version); |
|||
this.type = type; |
|||
this.assetProfileId = assetProfileId; |
|||
this.label = label; |
|||
this.additionalInfo = getText(additionalInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class AssetProfileFields extends AbstractEntityFields { |
|||
|
|||
private boolean isDefault; |
|||
|
|||
public AssetProfileFields(UUID id, long createdTime, UUID tenantId, String name, Long version, boolean isDefault) { |
|||
super(id, createdTime, tenantId, null, name, version); |
|||
this.isDefault = isDefault; |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class CustomerFields extends AbstractEntityFields { |
|||
|
|||
private String additionalInfo; |
|||
private String country; |
|||
private String state; |
|||
private String city; |
|||
private String address; |
|||
private String address2; |
|||
private String zip; |
|||
private String phone; |
|||
private String email; |
|||
|
|||
public CustomerFields(UUID id, long createdTime, UUID tenantId, String name, Long version, JsonNode additionalInfo, |
|||
String country, String state, String city, String address, String address2, String zip, String phone, String email) { |
|||
super(id, createdTime, tenantId, name, version); |
|||
this.additionalInfo = getText(additionalInfo); |
|||
this.country = country; |
|||
this.state = state; |
|||
this.city = city; |
|||
this.address = address; |
|||
this.address2 = address2; |
|||
this.zip = zip; |
|||
this.phone = phone; |
|||
this.email = email; |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class DashboardFields extends AbstractEntityFields { |
|||
|
|||
private static ObjectMapper objectMapper = new ObjectMapper(); |
|||
private List<UUID> assignedCustomerIds; |
|||
|
|||
public DashboardFields(UUID id, long createdTime, UUID tenantId, String assignedCustomers, String name, Long version) { |
|||
super(id, createdTime, tenantId, name, version); |
|||
this.assignedCustomerIds = getCustomerIds(assignedCustomers); |
|||
} |
|||
|
|||
private static List<UUID> getCustomerIds(String assignedCustomers) { |
|||
List<UUID> ids = new ArrayList<>(); |
|||
if (assignedCustomers == null || assignedCustomers.isEmpty()) { |
|||
return ids; |
|||
} |
|||
try { |
|||
JsonNode rootNode = objectMapper.readTree(assignedCustomers); |
|||
for (JsonNode node : rootNode) { |
|||
String idStr = node.path("customerId").path("id").asText(); |
|||
if (!idStr.isEmpty()) { |
|||
ids.add(UUID.fromString(idStr)); |
|||
} |
|||
} |
|||
} catch (JsonProcessingException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
return ids; |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class DeviceFields extends AbstractEntityFields implements ProfileAwareFields { |
|||
|
|||
private String label; |
|||
private String type; |
|||
private UUID deviceProfileId; |
|||
private String additionalInfo; |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public String getProfileName() { |
|||
return type; |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public UUID getProfileId() { |
|||
return deviceProfileId; |
|||
} |
|||
|
|||
public DeviceFields(UUID id, long createdTime, UUID tenantId, UUID customerId, String name, Long version, String type, |
|||
String label, UUID deviceProfileId, JsonNode additionalInfo) { |
|||
super(id, createdTime, tenantId, customerId, name, version); |
|||
this.label = label; |
|||
this.type = type; |
|||
this.deviceProfileId = deviceProfileId; |
|||
this.additionalInfo = getText(additionalInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
import org.thingsboard.server.common.data.DeviceProfileType; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class DeviceProfileFields extends AbstractEntityFields { |
|||
|
|||
private String type; |
|||
private boolean isDefault; |
|||
|
|||
public DeviceProfileFields(UUID id, long createdTime, UUID tenantId, String name, Long version, DeviceProfileType type, boolean isDefault) { |
|||
super(id, createdTime, tenantId, null, name, version); |
|||
this.type = type.name(); |
|||
this.isDefault = isDefault; |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class EdgeFields extends AbstractEntityFields { |
|||
|
|||
private String type; |
|||
private String label; |
|||
private String additionalInfo; |
|||
|
|||
public EdgeFields(UUID id, long createdTime, UUID tenantId, UUID customerId, String name, Long version, |
|||
String type, String label, JsonNode additionalInfo) { |
|||
super(id, createdTime, tenantId, customerId, name, version); |
|||
this.type = type; |
|||
this.label = label; |
|||
this.additionalInfo = getText(additionalInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,179 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonInclude; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.UUID; |
|||
|
|||
@JsonInclude(JsonInclude.Include.NON_NULL) |
|||
public interface EntityFields { |
|||
|
|||
Logger log = LoggerFactory.getLogger(EntityFields.class); |
|||
|
|||
default UUID getId() { |
|||
return null; |
|||
} |
|||
|
|||
default UUID getTenantId() { |
|||
return null; |
|||
} |
|||
|
|||
default UUID getCustomerId() { |
|||
return null; |
|||
} |
|||
|
|||
default List<UUID> getAssignedCustomerIds() { |
|||
return Collections.emptyList(); |
|||
} |
|||
|
|||
default long getCreatedTime() { |
|||
return 0; |
|||
} |
|||
|
|||
default String getName() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getType() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getLabel() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getAdditionalInfo() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getEmail() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getCountry() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getState() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getCity() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getAddress() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getAddress2() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getZip() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getPhone() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getRegion() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getFirstName() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getLastName() { |
|||
return ""; |
|||
} |
|||
|
|||
default boolean isEdgeTemplate() { |
|||
return false; |
|||
} |
|||
|
|||
default String getConfiguration() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getSchedule() { |
|||
return ""; |
|||
} |
|||
|
|||
default EntityId getOriginatorId() { |
|||
return null; |
|||
} |
|||
|
|||
default String getQueueName() { |
|||
return ""; |
|||
} |
|||
|
|||
default String getServiceId() { |
|||
return ""; |
|||
} |
|||
|
|||
default boolean isDefault() { |
|||
return false; |
|||
} |
|||
|
|||
default UUID getOwnerId() { |
|||
return null; |
|||
} |
|||
|
|||
default Long getVersion() { |
|||
return null; |
|||
} |
|||
|
|||
default String getAsString(String key) { |
|||
return switch (key) { |
|||
case "createdTime" -> Long.toString(getCreatedTime()); |
|||
case "type" -> getType(); |
|||
case "label" -> getLabel(); |
|||
case "additionalInfo" -> getAdditionalInfo(); |
|||
case "email" -> getEmail(); |
|||
case "country" -> getCountry(); |
|||
case "state" -> getState(); |
|||
case "city" -> getCity(); |
|||
case "address" -> getAddress(); |
|||
case "address2" -> getAddress2(); |
|||
case "zip" -> getZip(); |
|||
case "phone" -> getPhone(); |
|||
case "region" -> getRegion(); |
|||
case "firstName" -> getFirstName(); |
|||
case "lastName" -> getLastName(); |
|||
case "edgeTemplate" -> Boolean.toString(isEdgeTemplate()); |
|||
case "configuration" -> getConfiguration(); |
|||
case "schedule" -> getSchedule(); |
|||
case "originatorId" -> getOriginatorId().getId().toString(); |
|||
case "originatorType" -> getOriginatorId().getEntityType().toString(); |
|||
case "queueName" -> getQueueName(); |
|||
case "serviceId" -> getServiceId(); |
|||
default -> { |
|||
log.warn("Unknown field '{}'", key); |
|||
yield null; |
|||
} |
|||
}; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class EntityIdFields implements EntityFields { |
|||
|
|||
private UUID id; |
|||
private Long version; |
|||
|
|||
public EntityIdFields(UUID id, Long version) { |
|||
this.id = id; |
|||
this.version = version; |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class EntityViewFields extends AbstractEntityFields { |
|||
|
|||
private String type; |
|||
private String additionalInfo; |
|||
|
|||
public EntityViewFields(UUID id, long createdTime, UUID tenantId, UUID customerId, String name, String type, String additionalInfo, Long version) { |
|||
super(id, createdTime, tenantId, customerId, name, version); |
|||
this.type = type; |
|||
this.additionalInfo = additionalInfo; |
|||
} |
|||
} |
|||
@ -0,0 +1,299 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import org.thingsboard.server.common.data.ApiUsageState; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.DeviceProfileType; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.EntityView; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.TenantProfile; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.queue.QueueStats; |
|||
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.WidgetsBundle; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public class FieldsUtil { |
|||
|
|||
public static EntityFields toFields(Object entity) { |
|||
if (entity instanceof Customer customer) { |
|||
return toFields(customer); |
|||
} else if (entity instanceof Tenant tenant) { |
|||
return toFields(tenant); |
|||
} else if (entity instanceof TenantProfile tenantProfile) { |
|||
return toFields(tenantProfile); |
|||
} else if (entity instanceof Device device) { |
|||
return toFields(device); |
|||
} else if (entity instanceof Asset asset) { |
|||
return toFields(asset); |
|||
} else if (entity instanceof Edge edge) { |
|||
return toFields(edge); |
|||
} else if (entity instanceof EntityView entityView) { |
|||
return toFields(entityView); |
|||
} else if (entity instanceof User user) { |
|||
return toFields(user); |
|||
} else if (entity instanceof Dashboard dashboard) { |
|||
return toFields(dashboard); |
|||
} else if (entity instanceof RuleChain ruleChain) { |
|||
return toFields(ruleChain); |
|||
} else if (entity instanceof RuleNode ruleNode) { |
|||
return toFields(ruleNode); |
|||
} else if (entity instanceof WidgetType widgetType) { |
|||
return toFields(widgetType); |
|||
} else if (entity instanceof WidgetsBundle widgetsBundle) { |
|||
return toFields(widgetsBundle); |
|||
} else if (entity instanceof DeviceProfile deviceProfile) { |
|||
return toFields(deviceProfile); |
|||
} else if (entity instanceof AssetProfile assetProfile) { |
|||
return toFields(assetProfile); |
|||
} else if (entity instanceof QueueStats queueStats) { |
|||
return toFields(queueStats); |
|||
} else if (entity instanceof ApiUsageState apiUsageState) { |
|||
return toFields(apiUsageState); |
|||
} else { |
|||
throw new IllegalArgumentException("Unsupported entity type: " + entity.getClass().getName()); |
|||
} |
|||
} |
|||
|
|||
private static CustomerFields toFields(Customer entity) { |
|||
return CustomerFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getTitle()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.email(entity.getEmail()) |
|||
.country(entity.getCountry()) |
|||
.state(entity.getState()) |
|||
.city(entity.getCity()) |
|||
.address(entity.getAddress()) |
|||
.address2(entity.getAddress2()) |
|||
.zip(entity.getZip()) |
|||
.phone(entity.getPhone()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static TenantFields toFields(Tenant entity) { |
|||
return TenantFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getTitle()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.email(entity.getEmail()) |
|||
.country(entity.getCountry()) |
|||
.state(entity.getState()) |
|||
.city(entity.getCity()) |
|||
.address(entity.getAddress()) |
|||
.address2(entity.getAddress2()) |
|||
.zip(entity.getZip()) |
|||
.phone(entity.getPhone()) |
|||
.region(entity.getRegion()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static TenantProfileFields toFields(TenantProfile tenantProfile) { |
|||
return TenantProfileFields.builder() |
|||
.id(tenantProfile.getUuidId()) |
|||
.createdTime(tenantProfile.getCreatedTime()) |
|||
.name(tenantProfile.getName()) |
|||
.isDefault(tenantProfile.isDefault()) |
|||
.build(); |
|||
} |
|||
|
|||
private static DeviceFields toFields(Device entity) { |
|||
return DeviceFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.customerId(getCustomerId(entity.getCustomerId())) |
|||
.name(entity.getName()) |
|||
.type(entity.getType()) |
|||
.deviceProfileId(entity.getDeviceProfileId().getId()) |
|||
.label(entity.getLabel()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static AssetFields toFields(Asset entity) { |
|||
return AssetFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.customerId(getCustomerId(entity.getCustomerId())) |
|||
.name(entity.getName()) |
|||
.type(entity.getType()) |
|||
.assetProfileId(entity.getAssetProfileId().getId()) |
|||
.label(entity.getLabel()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static EdgeFields toFields(Edge entity) { |
|||
return EdgeFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.customerId(getCustomerId(entity.getCustomerId())) |
|||
.name(entity.getName()) |
|||
.type(entity.getType()) |
|||
.label(entity.getLabel()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static EntityViewFields toFields(EntityView entity) { |
|||
return EntityViewFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.customerId(getCustomerId(entity.getCustomerId())) |
|||
.name(entity.getName()) |
|||
.type(entity.getType()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static UserFields toFields(User entity) { |
|||
return UserFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.customerId(getCustomerId(entity.getCustomerId())) |
|||
.firstName(entity.getFirstName()) |
|||
.lastName(entity.getLastName()) |
|||
.email(entity.getEmail()) |
|||
.phone(entity.getPhone()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static DashboardFields toFields(Dashboard entity) { |
|||
return DashboardFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getTitle()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static RuleChainFields toFields(RuleChain entity) { |
|||
return RuleChainFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getName()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static RuleNodeFields toFields(RuleNode entity) { |
|||
return RuleNodeFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getName()) |
|||
.additionalInfo(getText(entity.getAdditionalInfo())) |
|||
.build(); |
|||
} |
|||
|
|||
private static WidgetTypeFields toFields(WidgetType entity) { |
|||
return WidgetTypeFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getName()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static WidgetsBundleFields toFields(WidgetsBundle entity) { |
|||
return WidgetsBundleFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getName()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static AssetProfileFields toFields(AssetProfile entity) { |
|||
return AssetProfileFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getName()) |
|||
.isDefault(entity.isDefault()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static DeviceProfileFields toFields(DeviceProfile entity) { |
|||
return DeviceProfileFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.name(entity.getName()) |
|||
.type(DeviceProfileType.DEFAULT.name()) |
|||
.isDefault(entity.isDefault()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
private static QueueStatsFields toFields(QueueStats entity) { |
|||
return QueueStatsFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.queueName(entity.getQueueName()) |
|||
.serviceId(entity.getServiceId()) |
|||
.build(); |
|||
} |
|||
|
|||
private static ApiUsageStateFields toFields(ApiUsageState entity) { |
|||
return ApiUsageStateFields.builder() |
|||
.id(entity.getUuidId()) |
|||
.createdTime(entity.getCreatedTime()) |
|||
.customerId(entity.getEntityId().getEntityType() == EntityType.CUSTOMER ? entity.getEntityId().getId() : null) |
|||
.entityId(entity.getEntityId()) |
|||
.transportState(entity.getTransportState()) |
|||
.dbStorageState(entity.getDbStorageState()) |
|||
.reExecState(entity.getReExecState()) |
|||
.jsExecState(entity.getJsExecState()) |
|||
.tbelExecState(entity.getTbelExecState()) |
|||
.emailExecState(entity.getEmailExecState()) |
|||
.smsExecState(entity.getSmsExecState()) |
|||
.alarmExecState(entity.getAlarmExecState()) |
|||
.version(entity.getVersion()) |
|||
.build(); |
|||
} |
|||
|
|||
public static String getText(JsonNode node) { |
|||
return node != null ? node.asText() : ""; |
|||
} |
|||
|
|||
private static UUID getCustomerId(CustomerId customerId) { |
|||
return (customerId != null && !customerId.getId().equals(CustomerId.NULL_UUID)) ? customerId.getId() : null; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@NoArgsConstructor |
|||
public class GenericFields extends AbstractEntityFields { |
|||
|
|||
public GenericFields(UUID id, long createdTime, UUID tenantId, String name, Long version) { |
|||
super(id, createdTime, tenantId, name, version); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public interface ProfileAwareFields extends EntityFields { |
|||
|
|||
String getProfileName(); |
|||
|
|||
UUID getProfileId(); |
|||
|
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class QueueStatsFields extends AbstractEntityFields { |
|||
|
|||
private String queueName; |
|||
private String serviceId; |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return queueName + '_' + serviceId; |
|||
} |
|||
|
|||
public QueueStatsFields(UUID id, long createdTime, UUID tenantId, String queueName, String serviceId) { |
|||
super(id, createdTime, tenantId); |
|||
this.queueName = queueName; |
|||
this.serviceId = serviceId; |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class RuleChainFields extends AbstractEntityFields { |
|||
|
|||
private String additionalInfo; |
|||
|
|||
public RuleChainFields(UUID id, long createdTime, UUID tenantId, String name, Long version, JsonNode additionalInfo) { |
|||
super(id, createdTime, tenantId, name, version); |
|||
this.additionalInfo = getText(additionalInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class RuleNodeFields implements EntityFields { |
|||
|
|||
private UUID id; |
|||
private long createdTime; |
|||
private String name; |
|||
private String additionalInfo; |
|||
|
|||
public RuleNodeFields(UUID id, long createdTime, String name, JsonNode additionalInfo) { |
|||
this.id = id; |
|||
this.createdTime = createdTime; |
|||
this.name = name; |
|||
this.additionalInfo = getText(additionalInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class TenantFields extends AbstractEntityFields { |
|||
|
|||
private String additionalInfo; |
|||
private String country; |
|||
private String state; |
|||
private String city; |
|||
private String address; |
|||
private String address2; |
|||
private String zip; |
|||
private String phone; |
|||
private String email; |
|||
private String region; |
|||
|
|||
public TenantFields(UUID id, long createdTime, String name, Long version, |
|||
JsonNode additionalInfo, String country, String state, String city, String address, |
|||
String address2, String zip, String phone, String email, String region) { |
|||
super(id, createdTime, name, version); |
|||
this.additionalInfo = getText(additionalInfo); |
|||
this.country = country; |
|||
this.state = state; |
|||
this.city = city; |
|||
this.address = address; |
|||
this.address2 = address2; |
|||
this.zip = zip; |
|||
this.phone = phone; |
|||
this.email = email; |
|||
this.region = region; |
|||
} |
|||
|
|||
@Override |
|||
public UUID getTenantId() { |
|||
return getId(); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class TenantProfileFields extends AbstractEntityFields { |
|||
|
|||
private boolean isDefault; |
|||
|
|||
public TenantProfileFields(UUID id, long createdTime, String name, boolean isDefault) { |
|||
super(id, createdTime, TenantId.SYS_TENANT_ID.getId(), null, name, 0L); |
|||
this.isDefault = isDefault; |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
import static org.thingsboard.server.common.data.edqs.fields.FieldsUtil.getText; |
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class UserFields extends AbstractEntityFields { |
|||
|
|||
private String firstName; |
|||
private String lastName; |
|||
private String email; |
|||
private String phone; |
|||
private String additionalInfo; |
|||
|
|||
public UserFields(UUID id, long createdTime, UUID tenantId, UUID customerId, |
|||
Long version, String firstName, String lastName, String email, |
|||
String phone, JsonNode additionalInfo) { |
|||
super(id, createdTime, tenantId, customerId, version); |
|||
this.firstName = firstName; |
|||
this.lastName = lastName; |
|||
this.email = email; |
|||
this.phone = phone; |
|||
this.additionalInfo = getText(additionalInfo); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class WidgetTypeFields extends AbstractEntityFields { |
|||
|
|||
public WidgetTypeFields(UUID id, long createdTime, UUID tenantId, String name, Long version) { |
|||
super(id, createdTime, tenantId, name, version); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.fields; |
|||
|
|||
import lombok.NoArgsConstructor; |
|||
import lombok.experimental.SuperBuilder; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@NoArgsConstructor |
|||
@SuperBuilder |
|||
public class WidgetsBundleFields extends AbstractEntityFields { |
|||
|
|||
public WidgetsBundleFields(UUID id, long createdTime, UUID tenantId, String name, Long version) { |
|||
super(id, createdTime, tenantId, name, version); |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.query; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.thingsboard.server.common.data.query.EntityCountQuery; |
|||
import org.thingsboard.server.common.data.query.EntityDataQuery; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
@Builder |
|||
public class EdqsRequest { |
|||
|
|||
private EntityDataQuery entityDataQuery; |
|||
private EntityCountQuery entityCountQuery; |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.query; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
public class EdqsResponse { |
|||
|
|||
private PageData<EntityData> entityDataQueryResult; |
|||
private Long entityCountQueryResult; |
|||
private String error; |
|||
|
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.query; |
|||
|
|||
import lombok.Data; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.common.data.query.TsValue; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.Map; |
|||
|
|||
@Data |
|||
@RequiredArgsConstructor |
|||
public class QueryResult { |
|||
|
|||
private final EntityId entityId; |
|||
private final Map<EntityKeyType, Map<String, TsValue>> latest; |
|||
|
|||
public EntityData toOldEntityData() { |
|||
return new EntityData(entityId, latest, Collections.emptyMap(), Collections.emptyMap()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
<!-- |
|||
|
|||
Copyright © 2016-2025 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. |
|||
|
|||
--> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.thingsboard</groupId> |
|||
<version>4.0.0-SNAPSHOT</version> |
|||
<artifactId>common</artifactId> |
|||
</parent> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>edqs</artifactId> |
|||
<packaging>jar</packaging> |
|||
|
|||
<name>ThingsBoard EDQS API</name> |
|||
<url>https://thingsboard.io</url> |
|||
|
|||
<properties> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
<main.dir>${basedir}/../..</main.dir> |
|||
</properties> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>org.rocksdb</groupId> |
|||
<artifactId>rocksdbjni</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>proto</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>data</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>util</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>message</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>stats</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>cluster-api</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.thingsboard.common</groupId> |
|||
<artifactId>queue</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.github.ben-manes.caffeine</groupId> |
|||
<artifactId>caffeine</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework</groupId> |
|||
<artifactId>spring-context-support</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-autoconfigure</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
<distributionManagement> |
|||
<repository> |
|||
<id>thingsboard-repo-deploy</id> |
|||
<name>ThingsBoard Repo Deployment</name> |
|||
<url>https://repo.thingsboard.io/artifactory/libs-release-public</url> |
|||
</repository> |
|||
</distributionManagement> |
|||
|
|||
</project> |
|||
@ -0,0 +1,46 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.ApiUsageStateFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@ToString(callSuper = true) |
|||
public class ApiUsageStateData extends BaseEntityData<ApiUsageStateFields> { |
|||
|
|||
public ApiUsageStateData(UUID entityId) { |
|||
super(entityId); |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.API_USAGE_STATE; |
|||
} |
|||
|
|||
@Override |
|||
public String getEntityName() { |
|||
return getEntityOwnerName(); |
|||
} |
|||
|
|||
@Override |
|||
public String getEntityOwnerName() { |
|||
return repo.getOwnerName(fields.getEntityId()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.AssetFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@ToString(callSuper = true) |
|||
public class AssetData extends ProfileAwareData<AssetFields> { |
|||
|
|||
public AssetData(UUID id) { |
|||
super(id); |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.ASSET; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,180 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityFields; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.permission.QueryContext; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.edqs.data.dp.BoolDataPoint; |
|||
import org.thingsboard.server.common.data.edqs.DataPoint; |
|||
import org.thingsboard.server.edqs.data.dp.LongDataPoint; |
|||
import org.thingsboard.server.edqs.data.dp.StringDataPoint; |
|||
import org.thingsboard.server.edqs.query.DataKey; |
|||
import org.thingsboard.server.edqs.repo.TenantRepo; |
|||
|
|||
import java.util.Map; |
|||
import java.util.Objects; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
@ToString |
|||
public abstract class BaseEntityData<T extends EntityFields> implements EntityData<T> { |
|||
|
|||
@Getter |
|||
private final UUID id; |
|||
@Getter |
|||
protected final Map<Integer, DataPoint> serverAttrMap; |
|||
@Getter |
|||
private final Map<Integer, DataPoint> tMap; |
|||
|
|||
@Getter |
|||
@Setter |
|||
private volatile UUID customerId; |
|||
|
|||
@Setter |
|||
protected TenantRepo repo; |
|||
|
|||
@Getter |
|||
@Setter |
|||
protected volatile T fields; |
|||
|
|||
public BaseEntityData(UUID id) { |
|||
this.id = id; |
|||
this.serverAttrMap = new ConcurrentHashMap<>(); |
|||
this.tMap = new ConcurrentHashMap<>(); |
|||
} |
|||
|
|||
@Override |
|||
public DataPoint getAttr(Integer keyId, EntityKeyType entityKeyType) { |
|||
return switch (entityKeyType) { |
|||
case ATTRIBUTE, SERVER_ATTRIBUTE -> serverAttrMap.get(keyId); |
|||
default -> null; |
|||
}; |
|||
} |
|||
|
|||
@Override |
|||
public boolean putAttr(Integer keyId, AttributeScope scope, DataPoint value) { |
|||
return serverAttrMap.put(keyId, value) == null; |
|||
} |
|||
|
|||
@Override |
|||
public boolean removeAttr(Integer keyId, AttributeScope scope) { |
|||
return serverAttrMap.remove(keyId) != null; |
|||
} |
|||
|
|||
@Override |
|||
public DataPoint getTs(Integer keyId) { |
|||
return tMap.get(keyId); |
|||
} |
|||
|
|||
@Override |
|||
public boolean putTs(Integer keyId, DataPoint value) { |
|||
return tMap.put(keyId, value) == null; |
|||
} |
|||
|
|||
@Override |
|||
public boolean removeTs(Integer keyId) { |
|||
return tMap.remove(keyId) != null; |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getOwnerType() { |
|||
return customerId != null ? EntityType.CUSTOMER : EntityType.TENANT; |
|||
} |
|||
|
|||
@Override |
|||
public DataPoint getDataPoint(DataKey key, QueryContext ctx) { |
|||
return switch (key.type()) { |
|||
case TIME_SERIES -> getTs(key.keyId()); |
|||
case ATTRIBUTE, SERVER_ATTRIBUTE, CLIENT_ATTRIBUTE, SHARED_ATTRIBUTE -> getAttr(key.keyId(), key.type()); |
|||
case ENTITY_FIELD -> getField(key, ctx); |
|||
default -> throw new RuntimeException(key.type() + " not supported"); |
|||
}; |
|||
} |
|||
|
|||
private DataPoint getField(DataKey newKey, QueryContext ctx) { |
|||
if (fields == null) { |
|||
return null; |
|||
} |
|||
String key = newKey.key(); |
|||
return switch (key) { |
|||
case "createdTime" -> new LongDataPoint(System.currentTimeMillis(), fields.getCreatedTime()); |
|||
case "edgeTemplate" -> new BoolDataPoint(System.currentTimeMillis(), fields.isEdgeTemplate()); |
|||
case "parentId" -> new StringDataPoint(System.currentTimeMillis(), getRelatedParentId(ctx)); |
|||
default -> new StringDataPoint(System.currentTimeMillis(), getField(key), false); |
|||
}; |
|||
} |
|||
|
|||
@Override |
|||
public String getField(String name) { |
|||
if (fields == null) { |
|||
return null; |
|||
} |
|||
return switch (name) { |
|||
case "name" -> getEntityName(); |
|||
case "ownerName" -> getEntityOwnerName(); |
|||
case "ownerType" -> customerId != null ? EntityType.CUSTOMER.name() : EntityType.TENANT.name(); |
|||
case "entityType" -> Optional.ofNullable(getEntityType()).map(EntityType::name).orElse(""); |
|||
default -> fields.getAsString(name); |
|||
}; |
|||
} |
|||
|
|||
public String getEntityOwnerName() { |
|||
return repo.getOwnerName(getCustomerId() == null || CustomerId.NULL_UUID.equals(getCustomerId()) ? null : |
|||
new CustomerId(getCustomerId())); |
|||
} |
|||
|
|||
public String getEntityName() { |
|||
return getFields().getName(); |
|||
} |
|||
|
|||
private String getRelatedParentId(QueryContext ctx) { |
|||
return Optional.ofNullable(ctx.getRelatedParentIdMap().get(getId())) |
|||
.map(UUID::toString) |
|||
.orElse(""); |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public boolean isEmpty() { |
|||
return fields == null; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) return true; |
|||
if (o == null || getClass() != o.getClass()) return false; |
|||
BaseEntityData<?> that = (BaseEntityData<?>) o; |
|||
return Objects.equals(id, that.id); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.CustomerFields; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.Collections; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
|
|||
public class CustomerData extends BaseEntityData<CustomerFields> { |
|||
|
|||
private final ConcurrentMap<EntityType, ConcurrentMap<UUID, EntityData<?>>> entitiesById = new ConcurrentHashMap<>(); |
|||
|
|||
public CustomerData(UUID entityId) { |
|||
super(entityId); |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.CUSTOMER; |
|||
} |
|||
|
|||
public Collection<EntityData<?>> getEntities(EntityType entityType) { |
|||
var map = entitiesById.get(entityType); |
|||
if (map == null) { |
|||
return Collections.emptyList(); |
|||
} else { |
|||
return map.values(); |
|||
} |
|||
} |
|||
|
|||
public void addOrUpdate(EntityData<?> ed) { |
|||
entitiesById.computeIfAbsent(ed.getEntityType(), et -> new ConcurrentHashMap<>()).put(ed.getId(), ed); |
|||
} |
|||
|
|||
public boolean remove(EntityData<?> ed) { |
|||
var map = entitiesById.get(ed.getEntityType()); |
|||
if (map != null) { |
|||
return map.remove(ed.getId()) != null; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.DeviceFields; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.common.data.edqs.DataPoint; |
|||
|
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
@ToString(callSuper = true) |
|||
public class DeviceData extends ProfileAwareData<DeviceFields> { |
|||
|
|||
private final Map<Integer, DataPoint> clientAttrMap; |
|||
private final Map<Integer, DataPoint> sharedAttrMap; |
|||
|
|||
public DeviceData(UUID entityId) { |
|||
super(entityId); |
|||
this.clientAttrMap = new ConcurrentHashMap<>(); |
|||
this.sharedAttrMap = new ConcurrentHashMap<>(); |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.DEVICE; |
|||
} |
|||
|
|||
@Override |
|||
public DataPoint getAttr(Integer keyId, EntityKeyType entityKeyType) { |
|||
return switch (entityKeyType) { |
|||
case ATTRIBUTE -> getAttributeDataPoint(keyId); |
|||
case SERVER_ATTRIBUTE -> serverAttrMap.get(keyId); |
|||
case CLIENT_ATTRIBUTE -> clientAttrMap.get(keyId); |
|||
case SHARED_ATTRIBUTE -> sharedAttrMap.get(keyId); |
|||
default -> throw new RuntimeException(entityKeyType + " not implemented"); |
|||
}; |
|||
} |
|||
|
|||
@Override |
|||
public boolean putAttr(Integer keyId, AttributeScope scope, DataPoint value) { |
|||
return switch (scope) { |
|||
case SERVER_SCOPE -> serverAttrMap.put(keyId, value) == null; |
|||
case CLIENT_SCOPE -> clientAttrMap.put(keyId, value) == null; |
|||
case SHARED_SCOPE -> sharedAttrMap.put(keyId, value) == null; |
|||
}; |
|||
} |
|||
|
|||
@Override |
|||
public boolean removeAttr(Integer keyId, AttributeScope scope) { |
|||
return switch (scope) { |
|||
case SERVER_SCOPE -> serverAttrMap.remove(keyId) != null; |
|||
case CLIENT_SCOPE -> clientAttrMap.remove(keyId) != null; |
|||
case SHARED_SCOPE -> sharedAttrMap.remove(keyId) != null; |
|||
}; |
|||
} |
|||
|
|||
private DataPoint getAttributeDataPoint(Integer keyId) { |
|||
DataPoint dp = serverAttrMap.get(keyId); |
|||
if (dp == null) { |
|||
dp = sharedAttrMap.get(keyId); |
|||
if (dp == null) { |
|||
dp = clientAttrMap.get(keyId); |
|||
} |
|||
} |
|||
return dp; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import org.thingsboard.server.common.data.AttributeScope; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityFields; |
|||
import org.thingsboard.server.common.data.permission.QueryContext; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.common.data.edqs.DataPoint; |
|||
import org.thingsboard.server.edqs.query.DataKey; |
|||
import org.thingsboard.server.edqs.repo.TenantRepo; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public interface EntityData<T extends EntityFields> { |
|||
|
|||
UUID getId(); |
|||
|
|||
EntityType getEntityType(); |
|||
|
|||
UUID getCustomerId(); |
|||
|
|||
void setCustomerId(UUID customerId); |
|||
|
|||
void setRepo(TenantRepo repo); |
|||
|
|||
T getFields(); |
|||
|
|||
void setFields(T fields); |
|||
|
|||
DataPoint getAttr(Integer keyId, EntityKeyType entityKeyType); |
|||
|
|||
boolean putAttr(Integer keyId, AttributeScope scope, DataPoint value); |
|||
|
|||
boolean removeAttr(Integer keyId, AttributeScope scope); |
|||
|
|||
DataPoint getTs(Integer keyId); |
|||
|
|||
boolean putTs(Integer keyId, DataPoint value); |
|||
|
|||
boolean removeTs(Integer keyId); |
|||
|
|||
EntityType getOwnerType(); |
|||
|
|||
DataPoint getDataPoint(DataKey key, QueryContext queryContext); |
|||
|
|||
String getField(String name); |
|||
|
|||
boolean isEmpty(); |
|||
|
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@ToString(callSuper = true) |
|||
public class EntityProfileData extends BaseEntityData<EntityFields> { |
|||
|
|||
private final EntityType entityType; |
|||
|
|||
public EntityProfileData(UUID entityId, EntityType entityType) { |
|||
super(entityId); |
|||
this.entityType = entityType; |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return entityType; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.ToString; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.EntityFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@ToString(callSuper = true) |
|||
public class GenericData extends BaseEntityData<EntityFields> { |
|||
|
|||
private final EntityType entityType; |
|||
|
|||
public GenericData(EntityType entityType, UUID entityId) { |
|||
super(entityId); |
|||
this.entityType = entityType; |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return entityType; |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import org.thingsboard.server.common.data.edqs.fields.ProfileAwareFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public abstract class ProfileAwareData<T> extends BaseEntityData<ProfileAwareFields> { |
|||
|
|||
public ProfileAwareData(UUID id) { |
|||
super(id); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public record RelationData(UUID fromId, EntityType fromType, UUID toId, EntityType toType, String type, |
|||
RelationTypeGroup typeGroup) { |
|||
|
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class RelationInfo { |
|||
|
|||
private final String type; |
|||
private final EntityData<?> target; |
|||
|
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.Set; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
|
|||
@NoArgsConstructor |
|||
public class RelationsRepo { |
|||
|
|||
private final ConcurrentMap<UUID, Set<RelationInfo>> fromRelations = new ConcurrentHashMap<>(); |
|||
private final ConcurrentMap<UUID, Set<RelationInfo>> toRelations = new ConcurrentHashMap<>(); |
|||
|
|||
public boolean add(EntityData<?> from, EntityData<?> to, String type) { |
|||
boolean addedFromRelation = fromRelations.computeIfAbsent(from.getId(), k -> ConcurrentHashMap.newKeySet()).add(new RelationInfo(type, to)); |
|||
boolean addedToRelation = toRelations.computeIfAbsent(to.getId(), k -> ConcurrentHashMap.newKeySet()).add(new RelationInfo(type, from)); |
|||
return addedFromRelation || addedToRelation; |
|||
} |
|||
|
|||
public Set<RelationInfo> getFrom(UUID entityId) { |
|||
var result = fromRelations.get(entityId); |
|||
return result == null ? Collections.emptySet() : result; |
|||
} |
|||
|
|||
public Set<RelationInfo> getTo(UUID entityId) { |
|||
var result = toRelations.get(entityId); |
|||
return result == null ? Collections.emptySet() : result; |
|||
} |
|||
|
|||
public boolean remove(UUID from, UUID to, String type) { |
|||
boolean removedFromRelation = false; |
|||
boolean removedToRelation = false; |
|||
Set<RelationInfo> fromRelations = this.fromRelations.get(from); |
|||
if (fromRelations != null) { |
|||
removedFromRelation = fromRelations.removeIf(relationInfo -> relationInfo.getTarget().getId().equals(to) && relationInfo.getType().equals(type)); |
|||
} |
|||
Set<RelationInfo> toRelations = this.toRelations.get(to); |
|||
if (toRelations != null) { |
|||
removedToRelation = toRelations.removeIf(relationInfo -> relationInfo.getTarget().getId().equals(from) && relationInfo.getType().equals(type)); |
|||
} |
|||
return removedFromRelation || removedToRelation; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data; |
|||
|
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.edqs.fields.TenantFields; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public class TenantData extends BaseEntityData<TenantFields> { |
|||
|
|||
public TenantData(UUID entityId) { |
|||
super(entityId); |
|||
} |
|||
|
|||
@Override |
|||
public EntityType getEntityType() { |
|||
return EntityType.TENANT; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.edqs.DataPoint; |
|||
|
|||
@RequiredArgsConstructor |
|||
public abstract class AbstractDataPoint implements DataPoint { |
|||
|
|||
@Getter |
|||
private final long ts; |
|||
|
|||
@Override |
|||
public String getStr() { |
|||
throw new RuntimeException(NOT_SUPPORTED); |
|||
} |
|||
|
|||
@Override |
|||
public long getLong() { |
|||
throw new RuntimeException(NOT_SUPPORTED); |
|||
} |
|||
|
|||
@Override |
|||
public double getDouble() { |
|||
throw new RuntimeException(NOT_SUPPORTED); |
|||
} |
|||
|
|||
@Override |
|||
public boolean getBool() { |
|||
throw new RuntimeException(NOT_SUPPORTED); |
|||
} |
|||
|
|||
@Override |
|||
public String getJson() { |
|||
throw new RuntimeException(NOT_SUPPORTED); |
|||
} |
|||
|
|||
public String toString() { |
|||
return valueToString(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
|
|||
public class BoolDataPoint extends AbstractDataPoint { |
|||
|
|||
@Getter |
|||
private final boolean value; |
|||
|
|||
public BoolDataPoint(long ts, boolean value) { |
|||
super(ts); |
|||
this.value = value; |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.BOOLEAN; |
|||
} |
|||
|
|||
@Override |
|||
public boolean getBool() { |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
public String valueToString() { |
|||
return Boolean.toString(value); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
|
|||
public class CompressedJsonDataPoint extends CompressedStringDataPoint { |
|||
|
|||
public CompressedJsonDataPoint(long ts, byte[] compressedValue) { |
|||
super(ts, compressedValue); |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.JSON; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.SneakyThrows; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
import org.thingsboard.server.edqs.util.TbBytePool; |
|||
import org.xerial.snappy.Snappy; |
|||
|
|||
public class CompressedStringDataPoint extends AbstractDataPoint { |
|||
|
|||
public static final int MIN_STR_SIZE_TO_COMPRESS = 512; |
|||
@Getter |
|||
private final byte[] compressedValue; |
|||
|
|||
@SneakyThrows |
|||
public CompressedStringDataPoint(long ts, byte[] compressedValue) { |
|||
super(ts); |
|||
this.compressedValue = TbBytePool.intern(compressedValue); |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.STRING; |
|||
} |
|||
|
|||
@SneakyThrows |
|||
@Override |
|||
public String getStr() { |
|||
return Snappy.uncompressString(compressedValue); |
|||
} |
|||
|
|||
@Override |
|||
public String valueToString() { |
|||
return getStr(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
|
|||
public class DoubleDataPoint extends AbstractDataPoint { |
|||
|
|||
@Getter |
|||
private final double value; |
|||
|
|||
public DoubleDataPoint(long ts, double value) { |
|||
super(ts); |
|||
this.value = value; |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.DOUBLE; |
|||
} |
|||
|
|||
@Override |
|||
public double getDouble() { |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
public String valueToString() { |
|||
return Double.toString(value); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
import org.thingsboard.server.edqs.util.TbStringPool; |
|||
|
|||
public class JsonDataPoint extends AbstractDataPoint { |
|||
|
|||
@Getter |
|||
private final String value; |
|||
|
|||
public JsonDataPoint(long ts, String value) { |
|||
super(ts); |
|||
this.value = TbStringPool.intern(value); |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.JSON; |
|||
} |
|||
|
|||
@Override |
|||
public String getJson() { |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
public String valueToString() { |
|||
return value; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
|
|||
public class LongDataPoint extends AbstractDataPoint { |
|||
|
|||
@Getter |
|||
private final long value; |
|||
|
|||
public LongDataPoint(long ts, long value) { |
|||
super(ts); |
|||
this.value = value; |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.LONG; |
|||
} |
|||
|
|||
@Override |
|||
public long getLong() { |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
public double getDouble() { |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
public String valueToString() { |
|||
return Long.toString(value); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
/** |
|||
* Copyright © 2016-2025 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.edqs.data.dp; |
|||
|
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.kv.DataType; |
|||
import org.thingsboard.server.edqs.util.TbStringPool; |
|||
|
|||
public class StringDataPoint extends AbstractDataPoint { |
|||
|
|||
@Getter |
|||
private final String value; |
|||
|
|||
public StringDataPoint(long ts, String value) { |
|||
this(ts, value, true); |
|||
} |
|||
|
|||
public StringDataPoint(long ts, String value, boolean deduplicate) { |
|||
super(ts); |
|||
this.value = deduplicate ? TbStringPool.intern(value) : value; |
|||
} |
|||
|
|||
@Override |
|||
public DataType getType() { |
|||
return DataType.STRING; |
|||
} |
|||
|
|||
@Override |
|||
public String getStr() { |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
public String valueToString() { |
|||
return value; |
|||
} |
|||
|
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue