512 changed files with 29880 additions and 6575 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,201 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.fasterxml.jackson.databind.ObjectMapper; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.Getter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.HasName; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.alarm.AlarmInfo; |
|||
import org.thingsboard.server.common.data.alarm.AlarmQuery; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.AlarmId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
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.PageData; |
|||
import org.thingsboard.server.common.data.page.PageDataIterableByTenantIdEntityId; |
|||
import org.thingsboard.server.common.data.page.TimePageLink; |
|||
import org.thingsboard.server.dao.alarm.AlarmService; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.dao.customer.CustomerService; |
|||
import org.thingsboard.server.dao.device.ClaimDevicesService; |
|||
import org.thingsboard.server.dao.device.DeviceCredentialsService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.edge.EdgeService; |
|||
import org.thingsboard.server.dao.exception.DataValidationException; |
|||
import org.thingsboard.server.dao.exception.IncorrectParameterException; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.rule.RuleChainService; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.dao.tenant.TenantService; |
|||
import org.thingsboard.server.service.action.EntityActionService; |
|||
import org.thingsboard.server.service.edge.EdgeNotificationService; |
|||
import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
|||
|
|||
import javax.mail.MessagingException; |
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.Optional; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractTbEntityService { |
|||
|
|||
protected static final int DEFAULT_PAGE_SIZE = 1000; |
|||
|
|||
private static final ObjectMapper json = new ObjectMapper(); |
|||
|
|||
@Value("${server.log_controller_error_stack_trace}") |
|||
@Getter |
|||
private boolean logControllerErrorStackTrace; |
|||
@Value("${edges.enabled}") |
|||
@Getter |
|||
protected boolean edgesEnabled; |
|||
|
|||
@Autowired |
|||
protected DbCallbackExecutorService dbExecutor; |
|||
@Autowired |
|||
protected TbNotificationEntityService notificationEntityService; |
|||
@Autowired(required = false) |
|||
protected EdgeService edgeService; |
|||
@Autowired |
|||
protected AlarmService alarmService; |
|||
@Autowired |
|||
protected EntityActionService entityActionService; |
|||
@Autowired |
|||
protected DeviceService deviceService; |
|||
@Autowired |
|||
protected AssetService assetService; |
|||
@Autowired |
|||
protected DeviceCredentialsService deviceCredentialsService; |
|||
@Autowired |
|||
protected TenantService tenantService; |
|||
@Autowired |
|||
protected CustomerService customerService; |
|||
@Autowired |
|||
protected ClaimDevicesService claimDevicesService; |
|||
@Autowired |
|||
protected TbTenantProfileCache tenantProfileCache; |
|||
@Autowired |
|||
protected RuleChainService ruleChainService; |
|||
@Autowired |
|||
protected EdgeNotificationService edgeNotificationService; |
|||
|
|||
protected ListenableFuture<Void> removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) { |
|||
ListenableFuture<PageData<AlarmInfo>> alarmsFuture = |
|||
alarmService.findAlarms(tenantId, new AlarmQuery(entityId, new TimePageLink(Integer.MAX_VALUE), null, null, false)); |
|||
|
|||
ListenableFuture<List<AlarmId>> alarmIdsFuture = Futures.transform(alarmsFuture, page -> |
|||
page.getData().stream().map(AlarmInfo::getId).collect(Collectors.toList()), dbExecutor); |
|||
|
|||
return Futures.transform(alarmIdsFuture, ids -> { |
|||
ids.stream().map(alarmId -> alarmService.deleteAlarm(tenantId, alarmId)).collect(Collectors.toList()); |
|||
return null; |
|||
}, dbExecutor); |
|||
} |
|||
|
|||
protected <E extends HasName, I extends EntityId> void logEntityAction(User user, TenantId tenantId, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { |
|||
if (user != null) { |
|||
entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo); |
|||
} else if (e == null) { |
|||
entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo); |
|||
} |
|||
} |
|||
|
|||
protected <T> T checkNotNull(T reference) throws ThingsboardException { |
|||
return checkNotNull(reference, "Requested item wasn't found!"); |
|||
} |
|||
|
|||
protected <T> T checkNotNull(T reference, String notFoundMessage) throws ThingsboardException { |
|||
if (reference == null) { |
|||
throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND); |
|||
} |
|||
return reference; |
|||
} |
|||
|
|||
protected <T> T checkNotNull(Optional<T> reference) throws ThingsboardException { |
|||
return checkNotNull(reference, "Requested item wasn't found!"); |
|||
} |
|||
|
|||
protected <T> T checkNotNull(Optional<T> reference, String notFoundMessage) throws ThingsboardException { |
|||
if (reference.isPresent()) { |
|||
return reference.get(); |
|||
} else { |
|||
throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND); |
|||
} |
|||
} |
|||
|
|||
protected ThingsboardException handleException(Exception exception) { |
|||
return handleException(exception, true); |
|||
} |
|||
|
|||
protected ThingsboardException handleException(Exception exception, boolean logException) { |
|||
if (logException && logControllerErrorStackTrace) { |
|||
log.error("Error [{}]", exception.getMessage(), exception); |
|||
} |
|||
|
|||
String cause = ""; |
|||
if (exception.getCause() != null) { |
|||
cause = exception.getCause().getClass().getCanonicalName(); |
|||
} |
|||
|
|||
if (exception instanceof ThingsboardException) { |
|||
return (ThingsboardException) exception; |
|||
} else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException |
|||
|| exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) { |
|||
return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS); |
|||
} else if (exception instanceof MessagingException) { |
|||
return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL); |
|||
} else { |
|||
return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL); |
|||
} |
|||
} |
|||
|
|||
@SuppressWarnings("unchecked") |
|||
protected <I extends EntityId> I emptyId(EntityType entityType) { |
|||
return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); |
|||
} |
|||
|
|||
protected List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) { |
|||
if (!edgesEnabled) { |
|||
return null; |
|||
} |
|||
if (EntityType.EDGE.equals(entityId.getEntityType())) { |
|||
return Collections.singletonList(new EdgeId(entityId.getId())); |
|||
} |
|||
PageDataIterableByTenantIdEntityId<EdgeId> relatedEdgeIdsIterator = |
|||
new PageDataIterableByTenantIdEntityId<>(edgeService::findRelatedEdgeIdsByEntityId, tenantId, entityId, DEFAULT_PAGE_SIZE); |
|||
List<EdgeId> result = new ArrayList<>(); |
|||
for (EdgeId edgeId : relatedEdgeIdsIterator) { |
|||
result.add(edgeId); |
|||
} |
|||
return result; |
|||
} |
|||
} |
|||
@ -0,0 +1,309 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.DataConstants; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.HasName; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.common.msg.TbMsgDataType; |
|||
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.action.EntityActionService; |
|||
import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
@Service |
|||
@TbCoreComponent |
|||
@RequiredArgsConstructor |
|||
public class DefaultTbNotificationEntityService implements TbNotificationEntityService { |
|||
private static final ObjectMapper json = new ObjectMapper(); |
|||
|
|||
private final EntityActionService entityActionService; |
|||
private final TbClusterService tbClusterService; |
|||
private final GatewayNotificationsService gatewayNotificationsService; |
|||
|
|||
@Override |
|||
public <E extends HasName, I extends EntityId> void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, SecurityUser user, Exception e, |
|||
Object... additionalInfo) { |
|||
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo); |
|||
} |
|||
|
|||
@Override |
|||
public <E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, |
|||
CustomerId customerId, ActionType actionType, |
|||
List<EdgeId> relatedEdgeIds, |
|||
SecurityUser user, Object... additionalInfo) { |
|||
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); |
|||
sendDeleteNotificationMsg(tenantId, entityId, entity, relatedEdgeIds); |
|||
} |
|||
|
|||
@Override |
|||
public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, |
|||
CustomerId customerId, E entity, |
|||
ActionType actionType, |
|||
EdgeEventActionType edgeActionType, |
|||
SecurityUser user, boolean sendToEdge, |
|||
Object... additionalInfo) { |
|||
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); |
|||
|
|||
if (sendToEdge) { |
|||
sendEntityAssignToCustomerNotificationMsg(tenantId, entityId, customerId, edgeActionType); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public <E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId, |
|||
CustomerId customerId, EdgeId edgeId, |
|||
E entity, ActionType actionType, |
|||
EdgeEventActionType edgeActionType, |
|||
SecurityUser user, Object... additionalInfo) { |
|||
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); |
|||
sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeActionType); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) { |
|||
tbClusterService.onTenantChange(tenant, null); |
|||
tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), event); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyDeleteTenant(Tenant tenant) { |
|||
tbClusterService.onTenantDelete(tenant, null); |
|||
tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), ComponentLifecycleEvent.DELETED); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, |
|||
Device device, Device oldDevice, ActionType actionType, |
|||
SecurityUser user, Object... additionalInfo) { |
|||
tbClusterService.onDeviceUpdated(device, oldDevice); |
|||
logEntityAction(tenantId, deviceId, device, customerId, actionType, user, additionalInfo); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, |
|||
List<EdgeId> relatedEdgeIds, SecurityUser user, Object... additionalInfo) { |
|||
gatewayNotificationsService.onDeviceDeleted(device); |
|||
tbClusterService.onDeviceDeleted(device, null); |
|||
|
|||
notifyDeleteEntity(tenantId, deviceId, device, customerId, ActionType.DELETED, relatedEdgeIds, user, false, additionalInfo); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, |
|||
DeviceCredentials deviceCredentials, SecurityUser user) { |
|||
tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceCredentials.getDeviceId(), deviceCredentials), null); |
|||
sendEntityNotificationMsg(tenantId, deviceId, EdgeEventActionType.CREDENTIALS_UPDATED); |
|||
logEntityAction(tenantId, deviceId, device, customerId, ActionType.CREDENTIALS_UPDATED, user, deviceCredentials); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId, |
|||
Device device, Tenant tenant, SecurityUser user, Object... additionalInfo) { |
|||
logEntityAction(tenantId, deviceId, device, customerId, ActionType.ASSIGNED_TO_TENANT, user, additionalInfo); |
|||
pushAssignedFromNotification(tenant, newTenantId, device); |
|||
} |
|||
|
|||
@Override |
|||
public <E extends HasName, I extends EntityId> void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, ActionType actionType, SecurityUser user, Object... additionalInfo) { |
|||
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo); |
|||
if (actionType == ActionType.UPDATED) { |
|||
sendEntityNotificationMsg(tenantId, entityId, EdgeEventActionType.UPDATED); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, |
|||
SecurityUser user, Object... additionalInfo) { |
|||
ComponentLifecycleEvent lifecycleEvent; |
|||
EdgeEventActionType edgeEventActionType = null; |
|||
switch (actionType) { |
|||
case ADDED: |
|||
lifecycleEvent = ComponentLifecycleEvent.CREATED; |
|||
break; |
|||
case UPDATED: |
|||
lifecycleEvent = ComponentLifecycleEvent.UPDATED; |
|||
break; |
|||
case ASSIGNED_TO_CUSTOMER: |
|||
lifecycleEvent = ComponentLifecycleEvent.UPDATED; |
|||
edgeEventActionType = EdgeEventActionType.ASSIGNED_TO_CUSTOMER; |
|||
break; |
|||
case UNASSIGNED_FROM_CUSTOMER: |
|||
lifecycleEvent = ComponentLifecycleEvent.UPDATED; |
|||
edgeEventActionType = EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER; |
|||
break; |
|||
case DELETED: |
|||
lifecycleEvent = ComponentLifecycleEvent.DELETED; |
|||
break; |
|||
default: |
|||
throw new IllegalArgumentException("Unknown actionType: " + actionType); |
|||
} |
|||
|
|||
tbClusterService.broadcastEntityStateChangeEvent(tenantId, edgeId, lifecycleEvent); |
|||
logEntityAction(tenantId, edgeId, edge, customerId, actionType, user, additionalInfo); |
|||
|
|||
//Send notification to edge
|
|||
if (edgeEventActionType != null) { |
|||
sendEntityAssignToCustomerNotificationMsg(tenantId, edgeId, customerId, edgeEventActionType); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo) { |
|||
logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo); |
|||
sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType (actionType)); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyDeleteAlarm(Alarm alarm, SecurityUser user, List<EdgeId> relatedEdgeIds) { |
|||
logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), ActionType.ALARM_DELETE, user, null); |
|||
sendAlarmDeleteNotificationMsg(alarm, relatedEdgeIds); |
|||
} |
|||
|
|||
@Override |
|||
public void notifyDeleteCustomer(Customer customer, SecurityUser user, List<EdgeId> edgeIds) { |
|||
logEntityAction(customer.getTenantId(), customer.getId(), customer, customer.getId(), ActionType.DELETED, user, null); |
|||
sendDeleteNotificationMsg(customer.getTenantId(), customer.getId(), customer, edgeIds); |
|||
tbClusterService.broadcastEntityStateChangeEvent(customer.getTenantId(), customer.getId(), ComponentLifecycleEvent.DELETED); |
|||
} |
|||
|
|||
private <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, SecurityUser user, Object... additionalInfo) { |
|||
logEntityAction(tenantId, entityId, entity, customerId, actionType, user, null, additionalInfo); |
|||
} |
|||
|
|||
private <E extends HasName, I extends EntityId> void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, SecurityUser user, Exception e, Object... additionalInfo) { |
|||
if (user != null) { |
|||
entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo); |
|||
} else if (e == null) { |
|||
entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo); |
|||
} |
|||
} |
|||
|
|||
private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) { |
|||
sendNotificationMsgToEdgeService(tenantId, null, entityId, null, null, action); |
|||
} |
|||
|
|||
private void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) { |
|||
try { |
|||
sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e); |
|||
} |
|||
} |
|||
|
|||
protected <E extends HasName, I extends EntityId> void sendDeleteNotificationMsg(TenantId tenantId, I entityId, E entity, List<EdgeId> edgeIds) { |
|||
try { |
|||
sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to push delete " + entity.getClass().getName() + " msg to core: {}", entity, e); |
|||
} |
|||
} |
|||
|
|||
protected void sendAlarmDeleteNotificationMsg(Alarm alarm, List<EdgeId> relatedEdgeIds) { |
|||
try { |
|||
sendDeleteNotificationMsg(alarm.getTenantId(), alarm.getId(), relatedEdgeIds, json.writeValueAsString(alarm)); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to push delete alarm msg to core: {}", alarm, e); |
|||
} |
|||
} |
|||
|
|||
private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List<EdgeId> edgeIds, String body) { |
|||
if (edgeIds != null && !edgeIds.isEmpty()) { |
|||
for (EdgeId edgeId : edgeIds) { |
|||
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) { |
|||
sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, action); |
|||
} |
|||
|
|||
private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) { |
|||
tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action); |
|||
} |
|||
|
|||
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { |
|||
String data = entityToStr(assignedDevice); |
|||
if (data != null) { |
|||
TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data); |
|||
tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null); |
|||
} |
|||
} |
|||
|
|||
private TbMsgMetaData getMetaDataForAssignedFrom(Tenant tenant) { |
|||
TbMsgMetaData metaData = new TbMsgMetaData(); |
|||
metaData.putValue("assignedFromTenantId", tenant.getId().getId().toString()); |
|||
metaData.putValue("assignedFromTenantName", tenant.getName()); |
|||
return metaData; |
|||
} |
|||
|
|||
private <E extends HasName> String entityToStr(E entity) { |
|||
try { |
|||
return json.writeValueAsString(json.valueToTree(entity)); |
|||
} catch (JsonProcessingException e) { |
|||
log.warn("[{}] Failed to convert entity to string!", entity, e); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
private EdgeEventActionType edgeTypeByActionType (ActionType actionType) { |
|||
switch (actionType) { |
|||
case ADDED: |
|||
return EdgeEventActionType.ADDED; |
|||
case UPDATED: |
|||
return EdgeEventActionType.UPDATED; |
|||
case ALARM_ACK: |
|||
return EdgeEventActionType.ALARM_ACK; |
|||
case ALARM_CLEAR: |
|||
return EdgeEventActionType.ALARM_CLEAR; |
|||
case DELETED: |
|||
return EdgeEventActionType.DELETED; |
|||
default: |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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 org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.HasName; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface TbNotificationEntityService { |
|||
|
|||
<E extends HasName, I extends EntityId> void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, SecurityUser user, Exception e, |
|||
Object... additionalInfo); |
|||
|
|||
<E extends HasName, I extends EntityId> void notifyCreateOrUpdateEntity(TenantId tenantId, I entityId, E entity, |
|||
CustomerId customerId, ActionType actionType, |
|||
SecurityUser user, Object... additionalInfo); |
|||
|
|||
<E extends HasName, I extends EntityId> void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId, |
|||
ActionType actionType, List<EdgeId> relatedEdgeIds, SecurityUser user, |
|||
Object... additionalInfo); |
|||
|
|||
<E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId, |
|||
CustomerId customerId, E entity, |
|||
ActionType actionType, |
|||
EdgeEventActionType edgeActionType, |
|||
SecurityUser user, boolean sendToEdge, |
|||
Object... additionalInfo); |
|||
|
|||
<E extends HasName, I extends EntityId> void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId, |
|||
CustomerId customerId, EdgeId edgeId, |
|||
E entity, ActionType actionType, |
|||
EdgeEventActionType edgeActionType, |
|||
SecurityUser user, Object... additionalInfo); |
|||
|
|||
void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event); |
|||
|
|||
void notifyDeleteTenant(Tenant tenant); |
|||
|
|||
void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, |
|||
Device oldDevice, ActionType actionType, SecurityUser user, Object... additionalInfo); |
|||
|
|||
void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, |
|||
List<EdgeId> relatedEdgeIds, SecurityUser user, Object... additionalInfo); |
|||
|
|||
void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device, |
|||
DeviceCredentials deviceCredentials, SecurityUser user); |
|||
|
|||
void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId, |
|||
Device device, Tenant tenant, SecurityUser user, Object... additionalInfo); |
|||
|
|||
void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, SecurityUser user, Object... additionalInfo); |
|||
|
|||
void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo); |
|||
|
|||
void notifyDeleteAlarm(Alarm alarm, SecurityUser user, List<EdgeId> relatedEdgeIds); |
|||
|
|||
void notifyDeleteCustomer(Customer customer, SecurityUser user, List<EdgeId> relatedEdgeIds); |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.alarm; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService { |
|||
|
|||
@Override |
|||
public Alarm save(Alarm alarm, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
TenantId tenantId = alarm.getTenantId(); |
|||
try { |
|||
Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm).getAlarm()); |
|||
notificationEntityService.notifyCreateOrUpdateAlarm(savedAlarm, actionType, user); |
|||
return savedAlarm; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ALARM), alarm, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void ack(Alarm alarm, SecurityUser user) throws ThingsboardException { |
|||
try { |
|||
long ackTs = System.currentTimeMillis(); |
|||
alarmService.ackAlarm(user.getTenantId(), alarm.getId(), ackTs).get(); |
|||
alarm.setAckTs(ackTs); |
|||
alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK); |
|||
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void clear(Alarm alarm, SecurityUser user) throws ThingsboardException { |
|||
try { |
|||
long clearTs = System.currentTimeMillis(); |
|||
alarmService.clearAlarm(user.getTenantId(), alarm.getId(), null, clearTs).get(); |
|||
alarm.setClearTs(clearTs); |
|||
alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK); |
|||
notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException { |
|||
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(alarm.getTenantId(), alarm.getOriginator()); |
|||
notificationEntityService.notifyDeleteAlarm(alarm, user, relatedEdgeIds); |
|||
return alarmService.deleteAlarm(alarm.getTenantId(), alarm.getId()).isSuccessful(); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.alarm; |
|||
|
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.entitiy.SimpleTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
public interface TbAlarmService extends SimpleTbEntityService<Alarm> { |
|||
|
|||
void ack(Alarm alarm, SecurityUser user) throws ThingsboardException; |
|||
|
|||
void clear(Alarm alarm, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException; |
|||
} |
|||
@ -0,0 +1,163 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.asset; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService { |
|||
@Override |
|||
public Asset save(Asset asset, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
TenantId tenantId = asset.getTenantId(); |
|||
try { |
|||
Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); |
|||
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), asset, savedAsset.getCustomerId(), actionType, user); |
|||
return savedAsset; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), asset, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> delete(Asset asset, SecurityUser user) throws ThingsboardException { |
|||
TenantId tenantId = asset.getTenantId(); |
|||
AssetId assetId = asset.getId(); |
|||
try { |
|||
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId); |
|||
assetService.deleteAsset(tenantId, assetId); |
|||
notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), ActionType.DELETED, relatedEdgeIds, user, false, asset.toString()); |
|||
|
|||
return removeAlarmsByEntityId(tenantId, assetId); |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, |
|||
ActionType.DELETED, user, e, asset.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; |
|||
CustomerId customerId = customer.getId(); |
|||
try { |
|||
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId)); |
|||
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, |
|||
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName()); |
|||
|
|||
return savedAsset; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, |
|||
actionType, user, e, assetId.toString(), customerId.toString()); |
|||
|
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; |
|||
try { |
|||
Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId)); |
|||
CustomerId customerId = customer.getId(); |
|||
|
|||
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset, |
|||
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, |
|||
true, customerId.toString(), customer.getName()); |
|||
|
|||
return savedAsset; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, |
|||
actionType, user, e, assetId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; |
|||
try { |
|||
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); |
|||
Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId())); |
|||
|
|||
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset, |
|||
actionType, null, user, false, actionType.toString(), |
|||
publicCustomer.getId().toString(), publicCustomer.getName()); |
|||
|
|||
return savedAsset; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, |
|||
actionType, user, e, assetId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_EDGE; |
|||
EdgeId edgeId = edge.getId(); |
|||
try { |
|||
Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(tenantId, assetId, edgeId)); |
|||
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, savedAsset.getCustomerId(), |
|||
edgeId, savedAsset, actionType, EdgeEventActionType.ASSIGNED_TO_EDGE, user, assetId.toString(), edgeId.toString(), edge.getName()); |
|||
|
|||
return savedAsset; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, |
|||
actionType, user, e, assetId.toString(), edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; |
|||
AssetId assetId = asset.getId(); |
|||
EdgeId edgeId = edge.getId(); |
|||
try { |
|||
Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(tenantId, assetId, edgeId)); |
|||
|
|||
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(), |
|||
edgeId, asset, actionType, EdgeEventActionType.UNASSIGNED_FROM_EDGE, user, assetId.toString(), edgeId.toString(), edge.getName()); |
|||
return savedAsset; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null, |
|||
actionType, user, e, assetId.toString(), edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.asset; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.service.entitiy.SimpleTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
public interface TbAssetService extends SimpleTbEntityService<Asset> { |
|||
|
|||
ListenableFuture<Void> delete(Asset asset, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, SecurityUser user) throws ThingsboardException; |
|||
|
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.customer; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
public class DefaultTbCustomerService extends AbstractTbEntityService implements TbCustomerService { |
|||
|
|||
@Override |
|||
public Customer save(Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = customer.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
TenantId tenantId = customer.getTenantId(); |
|||
try { |
|||
Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer)); |
|||
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedCustomer.getId(), savedCustomer, savedCustomer.getId(), actionType, user); |
|||
return savedCustomer; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), customer, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void delete(Customer customer, SecurityUser user) throws ThingsboardException { |
|||
TenantId tenantId = customer.getTenantId(); |
|||
try { |
|||
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, customer.getId()); |
|||
customerService.deleteCustomer(tenantId, customer.getId()); |
|||
notificationEntityService.notifyDeleteCustomer(customer, user, relatedEdgeIds); |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.CUSTOMER), null, null, ActionType.DELETED, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.customer; |
|||
|
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.service.entitiy.SimpleTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
public interface TbCustomerService extends SimpleTbEntityService<Customer> { |
|||
|
|||
void delete(Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
} |
|||
@ -0,0 +1,279 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.device; |
|||
|
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import com.google.common.util.concurrent.MoreExecutors; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.device.claim.ClaimResponse; |
|||
import org.thingsboard.server.dao.device.claim.ClaimResult; |
|||
import org.thingsboard.server.dao.device.claim.ReclaimResult; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
import java.util.List; |
|||
|
|||
@AllArgsConstructor |
|||
@TbCoreComponent |
|||
@Service |
|||
@Slf4j |
|||
public class DefaultTbDeviceService extends AbstractTbEntityService implements TbDeviceService { |
|||
|
|||
@Override |
|||
public Device save(TenantId tenantId, Device device, Device oldDevice, String accessToken, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
try { |
|||
Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); |
|||
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(), |
|||
savedDevice, oldDevice, actionType, user); |
|||
|
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials credentials, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
try { |
|||
Device savedDevice = checkNotNull(deviceService.saveDeviceWithCredentials(device, credentials)); |
|||
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(), |
|||
savedDevice, device, actionType, user); |
|||
|
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<Void> deleteDevice(Device device, SecurityUser user) throws ThingsboardException { |
|||
TenantId tenantId = device.getTenantId(); |
|||
DeviceId deviceId = device.getId(); |
|||
try { |
|||
List<EdgeId> relatedEdgeIds = findRelatedEdgeIds(tenantId, deviceId); |
|||
deviceService.deleteDevice(tenantId, deviceId); |
|||
notificationEntityService.notifyDeleteDevice(tenantId, deviceId, device.getCustomerId(), device, |
|||
relatedEdgeIds, user, deviceId.toString()); |
|||
|
|||
return removeAlarmsByEntityId(tenantId, deviceId); |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
ActionType.DELETED, user, e, deviceId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; |
|||
CustomerId customerId = customer.getId(); |
|||
try { |
|||
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(user.getTenantId(), deviceId, customerId)); |
|||
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice, |
|||
actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName()); |
|||
|
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
actionType, user, e, deviceId.toString(), customerId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device unassignDeviceFromCustomer(Device device, Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; |
|||
TenantId tenantId = device.getTenantId(); |
|||
DeviceId deviceId = device.getId(); |
|||
try { |
|||
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(tenantId, deviceId)); |
|||
CustomerId customerId = customer.getId(); |
|||
|
|||
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice, |
|||
actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user, |
|||
true, customerId.toString(), customer.getName()); |
|||
|
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
actionType, user, e, deviceId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; |
|||
try { |
|||
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); |
|||
Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId())); |
|||
|
|||
notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice, |
|||
actionType, null, user, false, deviceId.toString(), |
|||
publicCustomer.getId().toString(), publicCustomer.getName()); |
|||
|
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
actionType, user, e, deviceId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.CREDENTIALS_READ; |
|||
TenantId tenantId = device.getTenantId(); |
|||
DeviceId deviceId = device.getId(); |
|||
try { |
|||
DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId)); |
|||
notificationEntityService.notifyEntity(tenantId, deviceId, device, device.getCustomerId(), |
|||
actionType, user, null, deviceId.toString()); |
|||
return deviceCredentials; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
actionType, user, e, deviceId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException { |
|||
TenantId tenantId = device.getTenantId(); |
|||
DeviceId deviceId = device.getId(); |
|||
try { |
|||
DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials)); |
|||
notificationEntityService.notifyUpdateDeviceCredentials(tenantId, deviceId, device.getCustomerId(), device, result, user); |
|||
return result; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
ActionType.CREDENTIALS_UPDATED, user, e, deviceCredentials); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException { |
|||
try { |
|||
ListenableFuture<ClaimResult> future = claimDevicesService.claimDevice(device, customerId, secretKey); |
|||
|
|||
return Futures.transform(future, result -> { |
|||
if (result != null && result.getResponse().equals(ClaimResponse.SUCCESS)) { |
|||
notificationEntityService.notifyEntity(tenantId, device.getId(), result.getDevice(), customerId, |
|||
ActionType.ASSIGNED_TO_CUSTOMER, user, null, device.getId().toString(), customerId.toString(), |
|||
customerService.findCustomerById(tenantId, customerId).getName()); |
|||
} |
|||
return result; |
|||
}, MoreExecutors.directExecutor()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException { |
|||
try { |
|||
ListenableFuture<ReclaimResult> future = claimDevicesService.reClaimDevice(tenantId, device); |
|||
|
|||
return Futures.transform(future, result -> { |
|||
Customer unassignedCustomer = result.getUnassignedCustomer(); |
|||
if (unassignedCustomer != null) { |
|||
notificationEntityService.notifyEntity(tenantId, device.getId(), device, device.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, user, null, |
|||
device.getId().toString(), unassignedCustomer.getId().toString(), unassignedCustomer.getName()); |
|||
} |
|||
return result; |
|||
}, MoreExecutors.directExecutor()); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device assignDeviceToTenant(Device device, Tenant newTenant, SecurityUser user) throws ThingsboardException { |
|||
TenantId tenantId = device.getTenantId(); |
|||
TenantId newTenantId = newTenant.getId(); |
|||
try { |
|||
Tenant tenant = tenantService.findTenantById(tenantId); |
|||
Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device); |
|||
|
|||
notificationEntityService.notifyAssignDeviceToTenant(tenantId, newTenantId, device.getId(), |
|||
assignedDevice.getCustomerId(), assignedDevice, tenant, user, newTenantId.toString(), newTenant.getName()); |
|||
|
|||
return assignedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
ActionType.ASSIGNED_TO_TENANT, user, e, newTenantId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_EDGE; |
|||
EdgeId edgeId = edge.getId(); |
|||
try { |
|||
Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(tenantId, deviceId, edgeId)); |
|||
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, savedDevice.getCustomerId(), |
|||
edgeId, savedDevice, actionType, EdgeEventActionType.ASSIGNED_TO_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName()); |
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
actionType, user, e, deviceId.toString(), edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE; |
|||
TenantId tenantId = device.getTenantId(); |
|||
DeviceId deviceId = device.getId(); |
|||
EdgeId edgeId = edge.getId(); |
|||
try { |
|||
Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId)); |
|||
|
|||
notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, device.getCustomerId(), |
|||
edgeId, device, actionType, EdgeEventActionType.UNASSIGNED_FROM_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName()); |
|||
return savedDevice; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null, |
|||
actionType, user, e, deviceId.toString(), edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.device; |
|||
|
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.dao.device.claim.ClaimResult; |
|||
import org.thingsboard.server.dao.device.claim.ReclaimResult; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
public interface TbDeviceService { |
|||
|
|||
Device save(TenantId tenantId, Device device, Device oldDevice, String accessToken, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException; |
|||
|
|||
ListenableFuture<Void> deleteDevice(Device device, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device unassignDeviceFromCustomer(Device device, Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, SecurityUser user) throws ThingsboardException; |
|||
|
|||
DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException; |
|||
|
|||
DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException; |
|||
|
|||
ListenableFuture<ClaimResult> claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException; |
|||
|
|||
ListenableFuture<ReclaimResult> reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device assignDeviceToTenant(Device device, Tenant newTenant, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException; |
|||
} |
|||
@ -0,0 +1,150 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.edge; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.audit.ActionType; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
@AllArgsConstructor |
|||
@TbCoreComponent |
|||
@Service |
|||
@Slf4j |
|||
public class DefaultTbEdgeService extends AbstractTbEntityService implements TbEdgeService { |
|||
|
|||
@Override |
|||
public Edge saveEdge(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
|||
TenantId tenantId = edge.getTenantId(); |
|||
try { |
|||
Edge savedEdge = checkNotNull(edgeService.saveEdge(edge)); |
|||
EdgeId edgeId = savedEdge.getId(); |
|||
|
|||
if (actionType == ActionType.ADDED) { |
|||
ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), edgeId); |
|||
edgeNotificationService.setEdgeRootRuleChain(tenantId, savedEdge, edgeTemplateRootRuleChain.getId()); |
|||
edgeService.assignDefaultRuleChainsToEdge(tenantId, edgeId); |
|||
} |
|||
|
|||
notificationEntityService.notifyEdge(tenantId, edgeId, savedEdge.getCustomerId(), savedEdge, actionType, user); |
|||
|
|||
return savedEdge; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void deleteEdge(Edge edge, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.DELETED; |
|||
EdgeId edgeId = edge.getId(); |
|||
TenantId tenantId = edge.getTenantId(); |
|||
try { |
|||
edgeService.deleteEdge(tenantId, edgeId); |
|||
notificationEntityService.notifyEdge(tenantId, edgeId, edge.getCustomerId(), edge, actionType, user, edgeId.toString()); |
|||
|
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; |
|||
CustomerId customerId = customer.getId(); |
|||
try { |
|||
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId)); |
|||
|
|||
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user, |
|||
edgeId.toString(), customerId.toString(), customer.getName()); |
|||
|
|||
return savedEdge; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, |
|||
actionType, user, e, edgeId.toString(), customerId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER; |
|||
TenantId tenantId = edge.getTenantId(); |
|||
EdgeId edgeId = edge.getId(); |
|||
CustomerId customerId = customer.getId(); |
|||
try { |
|||
Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(tenantId, edgeId)); |
|||
|
|||
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user, |
|||
edgeId.toString(), customerId.toString(), customer.getName()); |
|||
return savedEdge; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, |
|||
actionType, user, e, edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER; |
|||
try { |
|||
Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId); |
|||
CustomerId customerId = publicCustomer.getId(); |
|||
Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId)); |
|||
|
|||
notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user, |
|||
edgeId.toString(), customerId.toString(), publicCustomer.getName()); |
|||
|
|||
return savedEdge; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, |
|||
actionType, user, e, edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException { |
|||
ActionType actionType = ActionType.UPDATED; |
|||
TenantId tenantId = edge.getTenantId(); |
|||
EdgeId edgeId = edge.getId(); |
|||
try { |
|||
Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, ruleChainId); |
|||
notificationEntityService.notifyEdge(tenantId, edgeId, null, updatedEdge, actionType, user); |
|||
return updatedEdge; |
|||
} catch (Exception e) { |
|||
notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null, |
|||
actionType, user, e, edgeId.toString()); |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.edge; |
|||
|
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.EdgeId; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.service.security.model.SecurityUser; |
|||
|
|||
public interface TbEdgeService { |
|||
Edge saveEdge(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException; |
|||
|
|||
void deleteEdge(Edge edge, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException; |
|||
|
|||
Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException; |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.tenant; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
|||
import org.thingsboard.server.service.install.InstallScripts; |
|||
|
|||
@Service |
|||
@TbCoreComponent |
|||
@AllArgsConstructor |
|||
public class DefaultTbTenantService extends AbstractTbEntityService implements TbTenantService { |
|||
|
|||
@Autowired |
|||
private InstallScripts installScripts; |
|||
|
|||
@Override |
|||
public Tenant save(Tenant tenant) throws ThingsboardException { |
|||
try { |
|||
boolean newTenant = tenant.getId() == null; |
|||
Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant)); |
|||
if (newTenant) { |
|||
installScripts.createDefaultRuleChains(savedTenant.getId()); |
|||
installScripts.createDefaultEdgeRuleChains(savedTenant.getId()); |
|||
} |
|||
tenantProfileCache.evict(savedTenant.getId()); |
|||
notificationEntityService.notifyCreateOruUpdateTenant(savedTenant, newTenant ? |
|||
ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); |
|||
return savedTenant; |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void delete(Tenant tenant) throws ThingsboardException { |
|||
try { |
|||
TenantId tenantId = tenant.getId(); |
|||
tenantService.deleteTenant(tenantId); |
|||
tenantProfileCache.evict(tenantId); |
|||
notificationEntityService.notifyDeleteTenant(tenant); |
|||
} catch (Exception e) { |
|||
throw handleException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.session; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) |
|||
@Service("SessionCache") |
|||
public class SessionCaffeineCache extends CaffeineTbTransactionalCache<DeviceId, TransportProtos.DeviceSessionsCacheEntry> { |
|||
|
|||
public SessionCaffeineCache(CacheManager cacheManager) { |
|||
super(cacheManager, CacheConstants.SESSIONS_CACHE); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.session; |
|||
|
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
|||
import org.springframework.data.redis.serializer.RedisSerializer; |
|||
import org.springframework.data.redis.serializer.SerializationException; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.cache.CacheSpecsMap; |
|||
import org.thingsboard.server.cache.TBRedisCacheConfiguration; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.cache.RedisTbTransactionalCache; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") |
|||
@Service("SessionCache") |
|||
public class SessionRedisCache extends RedisTbTransactionalCache<DeviceId, TransportProtos.DeviceSessionsCacheEntry> { |
|||
|
|||
public SessionRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { |
|||
super(CacheConstants.ASSET_CACHE, cacheSpecsMap, connectionFactory, configuration, new RedisSerializer<>() { |
|||
@Override |
|||
public byte[] serialize(TransportProtos.DeviceSessionsCacheEntry deviceSessionsCacheEntry) throws SerializationException { |
|||
return deviceSessionsCacheEntry.toByteArray(); |
|||
} |
|||
|
|||
@Override |
|||
public TransportProtos.DeviceSessionsCacheEntry deserialize(byte[] bytes) throws SerializationException { |
|||
try { |
|||
return TransportProtos.DeviceSessionsCacheEntry.parseFrom(bytes); |
|||
} catch (InvalidProtocolBufferException e) { |
|||
throw new RuntimeException("Failed to deserialize session cache entry"); |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -1,257 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.actors; |
|||
|
|||
import org.junit.jupiter.api.Test; |
|||
import org.junit.jupiter.api.extension.ExtendWith; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
|||
import org.springframework.boot.test.mock.mockito.MockBean; |
|||
import org.springframework.data.redis.core.RedisTemplate; |
|||
import org.springframework.test.context.ContextConfiguration; |
|||
import org.springframework.test.context.TestPropertySource; |
|||
import org.springframework.test.context.junit.jupiter.SpringExtension; |
|||
import org.thingsboard.rule.engine.api.MailService; |
|||
import org.thingsboard.rule.engine.api.SmsService; |
|||
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; |
|||
import org.thingsboard.server.actors.service.ActorService; |
|||
import org.thingsboard.server.cluster.TbClusterService; |
|||
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.dao.attributes.AttributesService; |
|||
import org.thingsboard.server.dao.audit.AuditLogService; |
|||
import org.thingsboard.server.dao.cassandra.CassandraCluster; |
|||
import org.thingsboard.server.dao.customer.CustomerService; |
|||
import org.thingsboard.server.dao.dashboard.DashboardService; |
|||
import org.thingsboard.server.dao.device.ClaimDevicesService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.edge.EdgeEventService; |
|||
import org.thingsboard.server.dao.edge.EdgeService; |
|||
import org.thingsboard.server.dao.entityview.EntityViewService; |
|||
import org.thingsboard.server.dao.event.EventService; |
|||
import org.thingsboard.server.dao.nosql.CassandraBufferedRateReadExecutor; |
|||
import org.thingsboard.server.dao.nosql.CassandraBufferedRateWriteExecutor; |
|||
import org.thingsboard.server.dao.ota.OtaPackageService; |
|||
import org.thingsboard.server.dao.relation.RelationService; |
|||
import org.thingsboard.server.dao.resource.ResourceService; |
|||
import org.thingsboard.server.dao.rule.RuleChainService; |
|||
import org.thingsboard.server.dao.rule.RuleNodeStateService; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.dao.tenant.TenantProfileService; |
|||
import org.thingsboard.server.dao.tenant.TenantService; |
|||
import org.thingsboard.server.dao.timeseries.TimeseriesService; |
|||
import org.thingsboard.server.dao.user.UserService; |
|||
import org.thingsboard.server.queue.discovery.PartitionService; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.usagestats.TbApiUsageClient; |
|||
import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
|||
import org.thingsboard.server.service.component.ComponentDiscoveryService; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeRpcService; |
|||
import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
|||
import org.thingsboard.server.service.executors.ExternalCallExecutorService; |
|||
import org.thingsboard.server.service.executors.SharedEventLoopGroupService; |
|||
import org.thingsboard.server.service.mail.MailExecutorService; |
|||
import org.thingsboard.server.service.profile.TbDeviceProfileCache; |
|||
import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; |
|||
import org.thingsboard.server.service.rpc.TbRpcService; |
|||
import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; |
|||
import org.thingsboard.server.service.script.JsInvokeService; |
|||
import org.thingsboard.server.service.session.DeviceSessionCacheService; |
|||
import org.thingsboard.server.service.sms.SmsExecutorService; |
|||
import org.thingsboard.server.service.state.DeviceStateService; |
|||
import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; |
|||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
|||
import org.thingsboard.server.service.transport.TbCoreToTransportService; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
|
|||
@ExtendWith(SpringExtension.class) |
|||
@ContextConfiguration(classes = ActorSystemContext.class) |
|||
@EnableConfigurationProperties |
|||
@TestPropertySource(properties = { |
|||
"cache.type=caffeine", |
|||
}) |
|||
public class ActorSystemContextTest { |
|||
|
|||
@Autowired |
|||
ActorSystemContext ctx; |
|||
|
|||
@MockBean |
|||
private TbApiUsageStateService apiUsageStateService; |
|||
|
|||
@MockBean |
|||
private TbApiUsageClient apiUsageClient; |
|||
|
|||
@MockBean |
|||
private TbServiceInfoProvider serviceInfoProvider; |
|||
|
|||
@MockBean |
|||
private ActorService actorService; |
|||
|
|||
@MockBean |
|||
private ComponentDiscoveryService componentService; |
|||
|
|||
@MockBean |
|||
private DataDecodingEncodingService encodingService; |
|||
|
|||
@MockBean |
|||
private DeviceService deviceService; |
|||
|
|||
@MockBean |
|||
private TbTenantProfileCache tenantProfileCache; |
|||
|
|||
@MockBean |
|||
private TbDeviceProfileCache deviceProfileCache; |
|||
|
|||
@MockBean |
|||
private AssetService assetService; |
|||
|
|||
@MockBean |
|||
private DashboardService dashboardService; |
|||
|
|||
@MockBean |
|||
private TenantService tenantService; |
|||
|
|||
@MockBean |
|||
private TenantProfileService tenantProfileService; |
|||
|
|||
@MockBean |
|||
private CustomerService customerService; |
|||
|
|||
@MockBean |
|||
private UserService userService; |
|||
|
|||
@MockBean |
|||
private RuleChainService ruleChainService; |
|||
|
|||
@MockBean |
|||
private RuleNodeStateService ruleNodeStateService; |
|||
|
|||
@MockBean |
|||
private PartitionService partitionService; |
|||
|
|||
@MockBean |
|||
private TbClusterService clusterService; |
|||
|
|||
@MockBean |
|||
private TimeseriesService tsService; |
|||
|
|||
@MockBean |
|||
private AttributesService attributesService; |
|||
|
|||
@MockBean |
|||
private EventService eventService; |
|||
|
|||
@MockBean |
|||
private RelationService relationService; |
|||
|
|||
@MockBean |
|||
private AuditLogService auditLogService; |
|||
|
|||
@MockBean |
|||
private EntityViewService entityViewService; |
|||
|
|||
@MockBean |
|||
private TelemetrySubscriptionService tsSubService; |
|||
|
|||
@MockBean |
|||
private AlarmSubscriptionService alarmService; |
|||
|
|||
@MockBean |
|||
private JsInvokeService jsSandbox; |
|||
|
|||
@MockBean |
|||
private MailExecutorService mailExecutor; |
|||
|
|||
@MockBean |
|||
private SmsExecutorService smsExecutor; |
|||
|
|||
@MockBean |
|||
private DbCallbackExecutorService dbCallbackExecutor; |
|||
|
|||
@MockBean |
|||
private ExternalCallExecutorService externalCallExecutorService; |
|||
|
|||
@MockBean |
|||
private SharedEventLoopGroupService sharedEventLoopGroupService; |
|||
|
|||
@MockBean |
|||
private MailService mailService; |
|||
|
|||
@MockBean |
|||
private SmsService smsService; |
|||
|
|||
@MockBean |
|||
private SmsSenderFactory smsSenderFactory; |
|||
|
|||
@MockBean |
|||
private ClaimDevicesService claimDevicesService; |
|||
|
|||
@MockBean |
|||
private JsInvokeStats jsInvokeStats; |
|||
|
|||
@MockBean |
|||
private DeviceStateService deviceStateService; |
|||
|
|||
@MockBean |
|||
private DeviceSessionCacheService deviceSessionCacheService; |
|||
|
|||
@MockBean |
|||
private TbCoreToTransportService tbCoreToTransportService; |
|||
|
|||
@MockBean |
|||
private TbRuleEngineDeviceRpcService tbRuleEngineDeviceRpcService; |
|||
|
|||
@MockBean |
|||
private TbCoreDeviceRpcService tbCoreDeviceRpcService; |
|||
|
|||
@MockBean |
|||
private EdgeService edgeService; |
|||
|
|||
@MockBean |
|||
private EdgeEventService edgeEventService; |
|||
|
|||
@MockBean |
|||
private EdgeRpcService edgeRpcService; |
|||
|
|||
@MockBean |
|||
private ResourceService resourceService; |
|||
|
|||
@MockBean |
|||
private OtaPackageService otaPackageService; |
|||
|
|||
@MockBean |
|||
private TbRpcService tbRpcService; |
|||
|
|||
@MockBean |
|||
private CassandraCluster cassandraCluster; |
|||
|
|||
@MockBean |
|||
private CassandraBufferedRateReadExecutor cassandraBufferedRateReadExecutor; |
|||
|
|||
@MockBean |
|||
private CassandraBufferedRateWriteExecutor cassandraBufferedRateWriteExecutor; |
|||
|
|||
@MockBean |
|||
private RedisTemplate<String, Object> redisTemplate; |
|||
|
|||
@Test |
|||
void givenCaffeineCache_whenInit_thenIsLocalCacheTrue() { |
|||
assertThat(ctx.getCacheType()).isEqualTo("caffeine"); |
|||
assertThat(ctx.isLocalCacheType()).as("caffeine is the local cache type").isTrue(); |
|||
} |
|||
|
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.BeforeClass; |
|||
import org.junit.extensions.cpsuite.ClasspathSuite; |
|||
import org.junit.runner.RunWith; |
|||
import org.thingsboard.server.queue.memory.InMemoryStorage; |
|||
|
|||
@RunWith(ClasspathSuite.class) |
|||
@ClasspathSuite.ClassnameFilters({ |
|||
// "org.thingsboard.server.controller.sql.WebsocketApiSqlTest",
|
|||
// "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest",
|
|||
// "org.thingsboard.server.controller.sql.TbResourceControllerSqlTest",
|
|||
// "org.thingsboard.server.controller.sql.DeviceProfileControllerSqlTest",
|
|||
"org.thingsboard.server.controller.sql.*Test", |
|||
}) |
|||
public class ControllerSqlTestSuite { |
|||
|
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.transport; |
|||
|
|||
import org.junit.extensions.cpsuite.ClasspathSuite; |
|||
import org.junit.runner.RunWith; |
|||
|
|||
@RunWith(ClasspathSuite.class) |
|||
@ClasspathSuite.ClassnameFilters({ |
|||
"org.thingsboard.server.transport.*.rpc.*Test", |
|||
"org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", |
|||
"org.thingsboard.server.transport.*.telemetry.attributes.*Test", |
|||
"org.thingsboard.server.transport.*.attributes.updates.*Test", |
|||
"org.thingsboard.server.transport.*.attributes.request.*Test", |
|||
"org.thingsboard.server.transport.*.claim.*Test", |
|||
"org.thingsboard.server.transport.*.provision.*Test", |
|||
"org.thingsboard.server.transport.*.credentials.*Test", |
|||
"org.thingsboard.server.transport.lwm2m.*.sql.*Test" |
|||
}) |
|||
public class TransportSqlTestSuite { |
|||
|
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.Setter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.LinkedHashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
public class CaffeineTbCacheTransaction<K extends Serializable, V extends Serializable> implements TbCacheTransaction<K, V> { |
|||
@Getter |
|||
private final UUID id = UUID.randomUUID(); |
|||
private final CaffeineTbTransactionalCache<K, V> cache; |
|||
@Getter |
|||
private final List<K> keys; |
|||
@Getter |
|||
@Setter |
|||
private boolean failed; |
|||
|
|||
private final Map<Object, Object> pendingPuts = new LinkedHashMap<>(); |
|||
|
|||
@Override |
|||
public void putIfAbsent(K key, V value) { |
|||
pendingPuts.put(key, value); |
|||
} |
|||
|
|||
@Override |
|||
public boolean commit() { |
|||
return cache.commit(id, pendingPuts); |
|||
} |
|||
|
|||
@Override |
|||
public void rollback() { |
|||
cache.rollback(id); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,193 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.CacheManager; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Collection; |
|||
import java.util.Collections; |
|||
import java.util.HashMap; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.locks.Lock; |
|||
import java.util.concurrent.locks.ReentrantLock; |
|||
|
|||
@RequiredArgsConstructor |
|||
public abstract class CaffeineTbTransactionalCache<K extends Serializable, V extends Serializable> implements TbTransactionalCache<K, V> { |
|||
|
|||
private final CacheManager cacheManager; |
|||
@Getter |
|||
private final String cacheName; |
|||
|
|||
private final Lock lock = new ReentrantLock(); |
|||
private final Map<K, Set<UUID>> objectTransactions = new HashMap<>(); |
|||
private final Map<UUID, CaffeineTbCacheTransaction<K, V>> transactions = new HashMap<>(); |
|||
|
|||
@Override |
|||
public TbCacheValueWrapper<V> get(K key) { |
|||
return SimpleTbCacheValueWrapper.wrap(cacheManager.getCache(cacheName).get(key)); |
|||
} |
|||
|
|||
@Override |
|||
public void put(K key, V value) { |
|||
lock.lock(); |
|||
try { |
|||
failAllTransactionsByKey(key); |
|||
cacheManager.getCache(cacheName).put(key, value); |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void putIfAbsent(K key, V value) { |
|||
lock.lock(); |
|||
try { |
|||
failAllTransactionsByKey(key); |
|||
doPutIfAbsent(key, value); |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void evict(K key) { |
|||
lock.lock(); |
|||
try { |
|||
failAllTransactionsByKey(key); |
|||
doEvict(key); |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void evict(Collection<K> keys) { |
|||
lock.lock(); |
|||
try { |
|||
keys.forEach(key -> { |
|||
failAllTransactionsByKey(key); |
|||
doEvict(key); |
|||
}); |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void evictOrPut(K key, V value) { |
|||
//No need to put the value in case of Caffeine, because evict will cancel concurrent transaction used to "get" the missing value from cache.
|
|||
evict(key); |
|||
} |
|||
|
|||
@Override |
|||
public TbCacheTransaction<K, V> newTransactionForKey(K key) { |
|||
return newTransaction(Collections.singletonList(key)); |
|||
} |
|||
|
|||
@Override |
|||
public TbCacheTransaction<K, V> newTransactionForKeys(List<K> keys) { |
|||
return newTransaction(keys); |
|||
} |
|||
|
|||
void doPutIfAbsent(Object key, Object value) { |
|||
cacheManager.getCache(cacheName).putIfAbsent(key, value); |
|||
} |
|||
|
|||
void doEvict(K key) { |
|||
cacheManager.getCache(cacheName).evict(key); |
|||
} |
|||
|
|||
TbCacheTransaction<K, V> newTransaction(List<K> keys) { |
|||
lock.lock(); |
|||
try { |
|||
var transaction = new CaffeineTbCacheTransaction<>(this, keys); |
|||
var transactionId = transaction.getId(); |
|||
for (K key : keys) { |
|||
objectTransactions.computeIfAbsent(key, k -> new HashSet<>()).add(transactionId); |
|||
} |
|||
transactions.put(transactionId, transaction); |
|||
return transaction; |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
public boolean commit(UUID trId, Map<Object, Object> pendingPuts) { |
|||
lock.lock(); |
|||
try { |
|||
var tr = transactions.get(trId); |
|||
var success = !tr.isFailed(); |
|||
if (success) { |
|||
for (K key : tr.getKeys()) { |
|||
Set<UUID> otherTransactions = objectTransactions.get(key); |
|||
if (otherTransactions != null) { |
|||
for (UUID otherTrId : otherTransactions) { |
|||
if (trId == null || !trId.equals(otherTrId)) { |
|||
transactions.get(otherTrId).setFailed(true); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
pendingPuts.forEach(this::doPutIfAbsent); |
|||
} |
|||
removeTransaction(trId); |
|||
return success; |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
void rollback(UUID id) { |
|||
lock.lock(); |
|||
try { |
|||
removeTransaction(id); |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
|
|||
private void removeTransaction(UUID id) { |
|||
CaffeineTbCacheTransaction<K, V> transaction = transactions.remove(id); |
|||
if (transaction != null) { |
|||
for (var key : transaction.getKeys()) { |
|||
Set<UUID> transactions = objectTransactions.get(key); |
|||
if (transactions != null) { |
|||
transactions.remove(id); |
|||
if (transactions.isEmpty()) { |
|||
objectTransactions.remove(key); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void failAllTransactionsByKey(K key) { |
|||
Set<UUID> transactionsIds = objectTransactions.get(key); |
|||
if (transactionsIds != null) { |
|||
for (UUID otherTrId : transactionsIds) { |
|||
transactions.get(otherTrId).setFailed(true); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.data.redis.connection.RedisConnection; |
|||
import org.springframework.data.redis.connection.RedisStringCommands; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
|
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
public class RedisTbCacheTransaction<K extends Serializable, V extends Serializable> implements TbCacheTransaction<K, V> { |
|||
|
|||
private final RedisTbTransactionalCache<K, V> cache; |
|||
private final RedisConnection connection; |
|||
|
|||
@Override |
|||
public void putIfAbsent(K key, V value) { |
|||
cache.put(connection, key, value, RedisStringCommands.SetOption.UPSERT); |
|||
} |
|||
|
|||
@Override |
|||
public boolean commit() { |
|||
try { |
|||
var execResult = connection.exec(); |
|||
var result = execResult != null && execResult.stream().anyMatch(Objects::nonNull); |
|||
return result; |
|||
} finally { |
|||
connection.close(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void rollback() { |
|||
try { |
|||
connection.discard(); |
|||
} finally { |
|||
connection.close(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,180 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.cache.support.NullValue; |
|||
import org.springframework.data.redis.connection.RedisConnection; |
|||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
|||
import org.springframework.data.redis.connection.RedisStringCommands; |
|||
import org.springframework.data.redis.core.types.Expiration; |
|||
import org.springframework.data.redis.serializer.RedisSerializer; |
|||
import org.springframework.data.redis.serializer.StringRedisSerializer; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Arrays; |
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
public abstract class RedisTbTransactionalCache<K extends Serializable, V extends Serializable> implements TbTransactionalCache<K, V> { |
|||
|
|||
private static final byte[] BINARY_NULL_VALUE = RedisSerializer.java().serialize(NullValue.INSTANCE); |
|||
|
|||
@Getter |
|||
private final String cacheName; |
|||
private final RedisConnectionFactory connectionFactory; |
|||
private final RedisSerializer<String> keySerializer = new StringRedisSerializer(); |
|||
private final RedisSerializer<V> valueSerializer; |
|||
private final Expiration evictExpiration; |
|||
private final Expiration cacheTtl; |
|||
|
|||
public RedisTbTransactionalCache(String cacheName, |
|||
CacheSpecsMap cacheSpecsMap, |
|||
RedisConnectionFactory connectionFactory, |
|||
TBRedisCacheConfiguration configuration, |
|||
RedisSerializer<V> valueSerializer) { |
|||
this.cacheName = cacheName; |
|||
this.connectionFactory = connectionFactory; |
|||
this.valueSerializer = valueSerializer; |
|||
this.evictExpiration = Expiration.from(configuration.getEvictTtlInMs(), TimeUnit.MILLISECONDS); |
|||
if (cacheSpecsMap.getSpecs() != null && cacheSpecsMap.getSpecs().get(cacheName) != null) { |
|||
CacheSpecs cacheSpecs = cacheSpecsMap.getSpecs().get(cacheName); |
|||
this.cacheTtl = Expiration.from(cacheSpecs.getTimeToLiveInMinutes(), TimeUnit.MINUTES); |
|||
} else { |
|||
this.cacheTtl = Expiration.persistent(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public TbCacheValueWrapper<V> get(K key) { |
|||
try (var connection = connectionFactory.getConnection()) { |
|||
byte[] rawKey = getRawKey(key); |
|||
byte[] rawValue = connection.get(rawKey); |
|||
if (rawValue == null) { |
|||
return null; |
|||
} else if (Arrays.equals(rawValue, BINARY_NULL_VALUE)) { |
|||
return SimpleTbCacheValueWrapper.empty(); |
|||
} else { |
|||
V value = valueSerializer.deserialize(rawValue); |
|||
return SimpleTbCacheValueWrapper.wrap(value); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void put(K key, V value) { |
|||
try (var connection = connectionFactory.getConnection()) { |
|||
put(connection, key, value, RedisStringCommands.SetOption.UPSERT); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void putIfAbsent(K key, V value) { |
|||
try (var connection = connectionFactory.getConnection()) { |
|||
put(connection, key, value, RedisStringCommands.SetOption.SET_IF_ABSENT); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void evict(K key) { |
|||
try (var connection = connectionFactory.getConnection()) { |
|||
connection.del(getRawKey(key)); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void evict(Collection<K> keys) { |
|||
try (var connection = connectionFactory.getConnection()) { |
|||
connection.del(keys.stream().map(this::getRawKey).toArray(byte[][]::new)); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void evictOrPut(K key, V value) { |
|||
try (var connection = connectionFactory.getConnection()) { |
|||
var rawKey = getRawKey(key); |
|||
var records = connection.del(rawKey); |
|||
if (records == null || records == 0) { |
|||
//We need to put the value in case of Redis, because evict will NOT cancel concurrent transaction used to "get" the missing value from cache.
|
|||
connection.set(rawKey, getRawValue(value), evictExpiration, RedisStringCommands.SetOption.UPSERT); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public TbCacheTransaction<K, V> newTransactionForKey(K key) { |
|||
byte[][] rawKey = new byte[][]{getRawKey(key)}; |
|||
RedisConnection connection = watch(rawKey); |
|||
return new RedisTbCacheTransaction<>(this, connection); |
|||
} |
|||
|
|||
@Override |
|||
public TbCacheTransaction<K, V> newTransactionForKeys(List<K> keys) { |
|||
RedisConnection connection = watch(keys.stream().map(this::getRawKey).toArray(byte[][]::new)); |
|||
return new RedisTbCacheTransaction<>(this, connection); |
|||
} |
|||
|
|||
private RedisConnection watch(byte[][] rawKeysList) { |
|||
var connection = connectionFactory.getConnection(); |
|||
try { |
|||
connection.watch(rawKeysList); |
|||
connection.multi(); |
|||
} catch (Exception e) { |
|||
connection.close(); |
|||
throw e; |
|||
} |
|||
return connection; |
|||
} |
|||
|
|||
private byte[] getRawKey(K key) { |
|||
String keyString = cacheName + key.toString(); |
|||
byte[] rawKey; |
|||
try { |
|||
rawKey = keySerializer.serialize(keyString); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to serialize the cache key: {}", key, e); |
|||
throw new RuntimeException(e); |
|||
} |
|||
if (rawKey == null) { |
|||
log.warn("Failed to serialize the cache key: {}", key); |
|||
throw new IllegalArgumentException("Failed to serialize the cache key!"); |
|||
} |
|||
return rawKey; |
|||
} |
|||
|
|||
private byte[] getRawValue(V value) { |
|||
if (value == null) { |
|||
return BINARY_NULL_VALUE; |
|||
} else { |
|||
try { |
|||
return valueSerializer.serialize(value); |
|||
} catch (Exception e) { |
|||
log.warn("Failed to serialize the cache value: {}", value, e); |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void put(RedisConnection connection, K key, V value, RedisStringCommands.SetOption setOption) { |
|||
byte[] rawKey = getRawKey(key); |
|||
byte[] rawValue = getRawValue(value); |
|||
connection.set(rawKey, rawValue, cacheTtl, setOption); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import lombok.AccessLevel; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.Cache; |
|||
|
|||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) |
|||
public class SimpleTbCacheValueWrapper<T> implements TbCacheValueWrapper<T> { |
|||
|
|||
private final T value; |
|||
|
|||
@Override |
|||
public T get() { |
|||
return value; |
|||
} |
|||
|
|||
public static <T> SimpleTbCacheValueWrapper<T> empty() { |
|||
return new SimpleTbCacheValueWrapper<>(null); |
|||
} |
|||
|
|||
public static <T> SimpleTbCacheValueWrapper<T> wrap(T value) { |
|||
return new SimpleTbCacheValueWrapper<>(value); |
|||
} |
|||
|
|||
@SuppressWarnings("unchecked") |
|||
public static <T> SimpleTbCacheValueWrapper<T> wrap(Cache.ValueWrapper source) { |
|||
return source == null ? null : new SimpleTbCacheValueWrapper<>((T) source.get()); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
public interface TbCacheValueWrapper<T> { |
|||
|
|||
T get(); |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import org.springframework.data.redis.serializer.RedisSerializer; |
|||
import org.springframework.data.redis.serializer.SerializationException; |
|||
|
|||
public class TbRedisSerializer<T> implements RedisSerializer<T> { |
|||
|
|||
private final RedisSerializer<Object> java = RedisSerializer.java(); |
|||
|
|||
@Override |
|||
public byte[] serialize(T t) throws SerializationException { |
|||
return java.serialize(t); |
|||
} |
|||
|
|||
@Override |
|||
public T deserialize(byte[] bytes) throws SerializationException { |
|||
return (T) java.deserialize(bytes); |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
import java.util.function.Function; |
|||
import java.util.function.Supplier; |
|||
|
|||
public interface TbTransactionalCache<K extends Serializable, V extends Serializable> { |
|||
|
|||
String getCacheName(); |
|||
|
|||
TbCacheValueWrapper<V> get(K key); |
|||
|
|||
void put(K key, V value); |
|||
|
|||
void putIfAbsent(K key, V value); |
|||
|
|||
void evict(K key); |
|||
|
|||
void evict(Collection<K> keys); |
|||
|
|||
void evictOrPut(K key, V value); |
|||
|
|||
TbCacheTransaction<K, V> newTransactionForKey(K key); |
|||
|
|||
TbCacheTransaction<K, V> newTransactionForKeys(List<K> keys); |
|||
|
|||
default V getAndPutInTransaction(K key, Supplier<V> dbCall, boolean cacheNullValue) { |
|||
TbCacheValueWrapper<V> cacheValueWrapper = get(key); |
|||
if (cacheValueWrapper != null) { |
|||
return cacheValueWrapper.get(); |
|||
} |
|||
var cacheTransaction = newTransactionForKey(key); |
|||
try { |
|||
V dbValue = dbCall.get(); |
|||
if (dbValue != null || cacheNullValue) { |
|||
cacheTransaction.putIfAbsent(key, dbValue); |
|||
cacheTransaction.commit(); |
|||
return dbValue; |
|||
} else { |
|||
cacheTransaction.rollback(); |
|||
return null; |
|||
} |
|||
} catch (Throwable e) { |
|||
cacheTransaction.rollback(); |
|||
throw e; |
|||
} |
|||
} |
|||
|
|||
default <R> R getAndPutInTransaction(K key, Supplier<R> dbCall, Function<V, R> cacheValueToResult, Function<R, V> dbValueToCacheValue, boolean cacheNullValue) { |
|||
TbCacheValueWrapper<V> cacheValueWrapper = get(key); |
|||
if (cacheValueWrapper != null) { |
|||
var cacheValue = cacheValueWrapper.get(); |
|||
return cacheValue == null ? null : cacheValueToResult.apply(cacheValue); |
|||
} |
|||
var cacheTransaction = newTransactionForKey(key); |
|||
try { |
|||
R dbValue = dbCall.get(); |
|||
if (dbValue != null || cacheNullValue) { |
|||
cacheTransaction.putIfAbsent(key, dbValueToCacheValue.apply(dbValue)); |
|||
cacheTransaction.commit(); |
|||
return dbValue; |
|||
} else { |
|||
cacheTransaction.rollback(); |
|||
return null; |
|||
} |
|||
} catch (Throwable e) { |
|||
cacheTransaction.rollback(); |
|||
throw e; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache.device; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.EqualsAndHashCode; |
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Getter |
|||
@EqualsAndHashCode |
|||
@RequiredArgsConstructor |
|||
@Builder |
|||
public class DeviceCacheKey implements Serializable { |
|||
|
|||
private final TenantId tenantId; |
|||
private final DeviceId deviceId; |
|||
private final String deviceName; |
|||
|
|||
public DeviceCacheKey(TenantId tenantId, DeviceId deviceId) { |
|||
this(tenantId, deviceId, null); |
|||
} |
|||
|
|||
public DeviceCacheKey(TenantId tenantId, String deviceName) { |
|||
this(tenantId, null, deviceName); |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
if (deviceId != null) { |
|||
return tenantId + "_" + deviceId; |
|||
} else { |
|||
return tenantId + "_n_" + deviceName; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache.device; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.Device; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) |
|||
@Service("DeviceCache") |
|||
public class DeviceCaffeineCache extends CaffeineTbTransactionalCache<DeviceCacheKey, Device> { |
|||
|
|||
public DeviceCaffeineCache(CacheManager cacheManager) { |
|||
super(cacheManager, CacheConstants.DEVICE_CACHE); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2022 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.cache.device; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.cache.CacheSpecsMap; |
|||
import org.thingsboard.server.cache.RedisTbTransactionalCache; |
|||
import org.thingsboard.server.cache.TBRedisCacheConfiguration; |
|||
import org.thingsboard.server.cache.TbRedisSerializer; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.Device; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") |
|||
@Service("DeviceCache") |
|||
public class DeviceRedisCache extends RedisTbTransactionalCache<DeviceCacheKey, Device> { |
|||
|
|||
public DeviceRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { |
|||
super(CacheConstants.DEVICE_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import lombok.Data; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
@Data |
|||
@RequiredArgsConstructor |
|||
class AssetCacheEvictEvent { |
|||
|
|||
private final TenantId tenantId; |
|||
private final String newName; |
|||
private final String oldName; |
|||
|
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.EqualsAndHashCode; |
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Getter |
|||
@EqualsAndHashCode |
|||
@RequiredArgsConstructor |
|||
@Builder |
|||
public class AssetCacheKey implements Serializable { |
|||
|
|||
private static final long serialVersionUID = 4196610233744512673L; |
|||
|
|||
private final TenantId tenantId; |
|||
private final String name; |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return tenantId + "_" + name; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) |
|||
@Service("AssetCache") |
|||
public class AssetCaffeineCache extends CaffeineTbTransactionalCache<AssetCacheKey, Asset> { |
|||
|
|||
public AssetCaffeineCache(CacheManager cacheManager) { |
|||
super(cacheManager, CacheConstants.ASSET_CACHE); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.asset; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.cache.CacheSpecsMap; |
|||
import org.thingsboard.server.cache.TBRedisCacheConfiguration; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.cache.RedisTbTransactionalCache; |
|||
import org.thingsboard.server.cache.TbRedisSerializer; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") |
|||
@Service("AssetCache") |
|||
public class AssetRedisCache extends RedisTbTransactionalCache<AssetCacheKey, Asset> { |
|||
|
|||
public AssetRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { |
|||
super(CacheConstants.ASSET_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.attributes; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
import org.thingsboard.server.cache.CaffeineTbTransactionalCache; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) |
|||
@Service("AttributeCache") |
|||
public class AttributeCaffeineCache extends CaffeineTbTransactionalCache<AttributeCacheKey, AttributeKvEntry> { |
|||
|
|||
public AttributeCaffeineCache(CacheManager cacheManager) { |
|||
super(cacheManager, CacheConstants.ATTRIBUTES_CACHE); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.attributes; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.cache.CacheSpecsMap; |
|||
import org.thingsboard.server.cache.TBRedisCacheConfiguration; |
|||
import org.thingsboard.server.common.data.CacheConstants; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
import org.thingsboard.server.cache.RedisTbTransactionalCache; |
|||
import org.thingsboard.server.cache.TbRedisSerializer; |
|||
|
|||
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") |
|||
@Service("AttributeCache") |
|||
public class AttributeRedisCache extends RedisTbTransactionalCache<AttributeCacheKey, AttributeKvEntry> { |
|||
|
|||
public AttributeRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { |
|||
super(CacheConstants.ATTRIBUTES_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbRedisSerializer<>()); |
|||
} |
|||
} |
|||
@ -1,63 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.attributes; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.cache.Cache; |
|||
import org.springframework.cache.CacheManager; |
|||
import org.springframework.context.annotation.Primary; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
|||
|
|||
import static org.thingsboard.server.common.data.CacheConstants.ATTRIBUTES_CACHE; |
|||
|
|||
@Service |
|||
@ConditionalOnProperty(prefix = "cache.attributes", value = "enabled", havingValue = "true") |
|||
@Primary |
|||
@Slf4j |
|||
public class AttributesCacheWrapper { |
|||
private final Cache attributesCache; |
|||
|
|||
public AttributesCacheWrapper(CacheManager cacheManager) { |
|||
this.attributesCache = cacheManager.getCache(ATTRIBUTES_CACHE); |
|||
} |
|||
|
|||
public Cache.ValueWrapper get(AttributeCacheKey attributeCacheKey) { |
|||
try { |
|||
return attributesCache.get(attributeCacheKey); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to retrieve element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage()); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public void put(AttributeCacheKey attributeCacheKey, AttributeKvEntry attributeKvEntry) { |
|||
try { |
|||
attributesCache.put(attributeCacheKey, attributeKvEntry); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to put element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage()); |
|||
} |
|||
} |
|||
|
|||
public void evict(AttributeCacheKey attributeCacheKey) { |
|||
try { |
|||
attributesCache.evict(attributeCacheKey); |
|||
} catch (Exception e) { |
|||
log.debug("Failed to evict element from cache for key {}. Reason - {}.", attributeCacheKey, e.getMessage()); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue