11 changed files with 270 additions and 73 deletions
@ -0,0 +1,149 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2024 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.cf; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import org.thingsboard.server.common.data.EntityType; |
||||
|
import org.thingsboard.server.common.data.HasTenantId; |
||||
|
import org.thingsboard.server.common.data.audit.ActionType; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedField; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedFieldConfig; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedFieldLink; |
||||
|
import org.thingsboard.server.common.data.exception.ThingsboardException; |
||||
|
import org.thingsboard.server.common.data.id.AssetId; |
||||
|
import org.thingsboard.server.common.data.id.AssetProfileId; |
||||
|
import org.thingsboard.server.common.data.id.CalculatedFieldId; |
||||
|
import org.thingsboard.server.common.data.id.CalculatedFieldLinkId; |
||||
|
import org.thingsboard.server.common.data.id.CustomerId; |
||||
|
import org.thingsboard.server.common.data.id.DeviceId; |
||||
|
import org.thingsboard.server.common.data.id.DeviceProfileId; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.id.HasId; |
||||
|
import org.thingsboard.server.common.data.id.TenantId; |
||||
|
import org.thingsboard.server.dao.cf.CalculatedFieldService; |
||||
|
import org.thingsboard.server.queue.util.TbCoreComponent; |
||||
|
import org.thingsboard.server.service.entitiy.AbstractTbEntityService; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
import org.thingsboard.server.service.security.permission.Operation; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.Objects; |
||||
|
import java.util.Optional; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
import static org.thingsboard.server.dao.service.Validator.validateEntityId; |
||||
|
|
||||
|
@TbCoreComponent |
||||
|
@Service |
||||
|
@Slf4j |
||||
|
public class DefaultTbCalculatedFieldService extends AbstractTbEntityService implements TbCalculatedFieldService { |
||||
|
|
||||
|
private final Map<CalculatedFieldId, CalculatedField> calculatedFields; |
||||
|
private final Map<CalculatedFieldLinkId, CalculatedFieldLink> calculatedFieldLinks; |
||||
|
private final CalculatedFieldService calculatedFieldService; |
||||
|
|
||||
|
public DefaultTbCalculatedFieldService(CalculatedFieldService calculatedFieldService) { |
||||
|
this.calculatedFields = calculatedFieldService.findAll().stream().collect(Collectors.toMap(CalculatedField::getId, cf -> cf)); |
||||
|
this.calculatedFieldLinks = calculatedFieldService.findAllCalculatedFieldLinks().stream().collect(Collectors.toMap(CalculatedFieldLink::getId, cfl -> cfl)); |
||||
|
this.calculatedFieldService = calculatedFieldService; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onMsg() { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public CalculatedField save(CalculatedField calculatedField, SecurityUser user) throws ThingsboardException { |
||||
|
ActionType actionType = calculatedField.getId() == null ? ActionType.ADDED : ActionType.UPDATED; |
||||
|
TenantId tenantId = calculatedField.getTenantId(); |
||||
|
try { |
||||
|
checkEntityExistence(tenantId, calculatedField.getEntityId()); |
||||
|
checkReferencedEntities(calculatedField.getConfiguration(), user); |
||||
|
CalculatedField savedCalculatedField = checkNotNull(calculatedFieldService.save(calculatedField)); |
||||
|
logEntityActionService.logEntityAction(tenantId, savedCalculatedField.getId(), savedCalculatedField, actionType, user); |
||||
|
return savedCalculatedField; |
||||
|
} catch (ThingsboardException e) { |
||||
|
logEntityActionService.logEntityAction(tenantId, emptyId(EntityType.CALCULATED_FIELD), calculatedField, actionType, user, e); |
||||
|
throw e; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public CalculatedField findById(CalculatedFieldId calculatedFieldId, SecurityUser user) { |
||||
|
return calculatedFieldService.findById(user.getTenantId(), calculatedFieldId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional |
||||
|
public void delete(CalculatedField calculatedField, SecurityUser user) { |
||||
|
ActionType actionType = ActionType.DELETED; |
||||
|
TenantId tenantId = calculatedField.getTenantId(); |
||||
|
CalculatedFieldId calculatedFieldId = calculatedField.getId(); |
||||
|
try { |
||||
|
calculatedFieldService.deleteCalculatedField(tenantId, calculatedFieldId); |
||||
|
logEntityActionService.logEntityAction(tenantId, calculatedFieldId, calculatedField, actionType, user, calculatedFieldId.toString()); |
||||
|
} catch (Exception e) { |
||||
|
logEntityActionService.logEntityAction(tenantId, emptyId(EntityType.CALCULATED_FIELD), actionType, user, e, calculatedFieldId.toString()); |
||||
|
throw e; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void checkEntityExistence(TenantId tenantId, EntityId entityId) { |
||||
|
switch (entityId.getEntityType()) { |
||||
|
case ASSET -> Optional.ofNullable(assetService.findAssetById(tenantId, (AssetId) entityId)) |
||||
|
.orElseThrow(() -> new IllegalArgumentException("Asset with id [" + entityId.getId() + "] does not exist.")); |
||||
|
case DEVICE -> Optional.ofNullable(deviceService.findDeviceById(tenantId, (DeviceId) entityId)) |
||||
|
.orElseThrow(() -> new IllegalArgumentException("Device with id [" + entityId.getId() + "] does not exist.")); |
||||
|
case ASSET_PROFILE -> |
||||
|
Optional.ofNullable(assetProfileService.findAssetProfileById(tenantId, (AssetProfileId) entityId)) |
||||
|
.orElseThrow(() -> new IllegalArgumentException("Asset Profile with id [" + entityId.getId() + "] does not exist.")); |
||||
|
case DEVICE_PROFILE -> |
||||
|
Optional.ofNullable(deviceProfileService.findDeviceProfileById(tenantId, (DeviceProfileId) entityId)) |
||||
|
.orElseThrow(() -> new IllegalArgumentException("Device Profile with id [" + entityId.getId() + "] does not exist.")); |
||||
|
default -> |
||||
|
throw new IllegalArgumentException("Entity type '" + entityId.getEntityType() + "' does not support calculated fields."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private <E extends HasId<I> & HasTenantId, I extends EntityId> void checkReferencedEntities(CalculatedFieldConfig calculatedFieldConfig, SecurityUser user) throws ThingsboardException { |
||||
|
List<EntityId> referencedEntityIds = calculatedFieldConfig.getArguments().values().stream() |
||||
|
.map(CalculatedFieldConfig.Argument::getEntityId) |
||||
|
.filter(Objects::nonNull) |
||||
|
.toList(); |
||||
|
for (EntityId referencedEntityId : referencedEntityIds) { |
||||
|
validateEntityId(referencedEntityId, id -> "Invalid entity id " + id); |
||||
|
E entity = findEntity(user.getTenantId(), referencedEntityId); |
||||
|
checkNotNull(entity); |
||||
|
checkEntity(user, entity, Operation.READ); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
private <E extends HasId<I> & HasTenantId, I extends EntityId> E findEntity(TenantId tenantId, EntityId entityId) { |
||||
|
return (E) switch (entityId.getEntityType()) { |
||||
|
case TENANT -> tenantService.findTenantById((TenantId) entityId); |
||||
|
case CUSTOMER -> customerService.findCustomerById(tenantId, (CustomerId) entityId); |
||||
|
case ASSET -> assetService.findAssetById(tenantId, (AssetId) entityId); |
||||
|
case DEVICE -> deviceService.findDeviceById(tenantId, (DeviceId) entityId); |
||||
|
default -> throw new IllegalArgumentException("Calculated fields do not support entity type '" + entityId.getEntityType() + "' for referenced entities."); |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2024 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.cf; |
||||
|
|
||||
|
import org.thingsboard.server.common.data.cf.CalculatedField; |
||||
|
import org.thingsboard.server.common.data.exception.ThingsboardException; |
||||
|
import org.thingsboard.server.common.data.id.CalculatedFieldId; |
||||
|
import org.thingsboard.server.service.security.model.SecurityUser; |
||||
|
|
||||
|
public interface TbCalculatedFieldService { |
||||
|
|
||||
|
void onMsg(); |
||||
|
|
||||
|
CalculatedField save(CalculatedField calculatedField, SecurityUser user) throws ThingsboardException; |
||||
|
|
||||
|
CalculatedField findById(CalculatedFieldId calculatedFieldId, SecurityUser user); |
||||
|
|
||||
|
void delete(CalculatedField calculatedField, SecurityUser user); |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue