implemented methods for calculated field update/delete in cluster service
This commit is contained in:
		
							parent
							
								
									4d8b62eb21
								
							
						
					
					
						commit
						3072861a8f
					
				@ -369,6 +369,10 @@
 | 
				
			|||||||
            <groupId>com.google.firebase</groupId>
 | 
					            <groupId>com.google.firebase</groupId>
 | 
				
			||||||
            <artifactId>firebase-admin</artifactId>
 | 
					            <artifactId>firebase-admin</artifactId>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.rocksdb</groupId>
 | 
				
			||||||
 | 
					            <artifactId>rocksdbjni</artifactId>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
    </dependencies>
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <build>
 | 
					    <build>
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.TbResourceInfo;
 | 
				
			|||||||
import org.thingsboard.server.common.data.Tenant;
 | 
					import org.thingsboard.server.common.data.Tenant;
 | 
				
			||||||
import org.thingsboard.server.common.data.TenantProfile;
 | 
					import org.thingsboard.server.common.data.TenantProfile;
 | 
				
			||||||
import org.thingsboard.server.common.data.audit.ActionType;
 | 
					import org.thingsboard.server.common.data.audit.ActionType;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
				
			||||||
import org.thingsboard.server.common.data.edge.Edge;
 | 
					import org.thingsboard.server.common.data.edge.Edge;
 | 
				
			||||||
import org.thingsboard.server.common.data.edge.EdgeEvent;
 | 
					import org.thingsboard.server.common.data.edge.EdgeEvent;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
					import org.thingsboard.server.common.data.id.DeviceId;
 | 
				
			||||||
@ -118,7 +119,11 @@ public class EntityStateSourcingListener {
 | 
				
			|||||||
                ApiUsageState apiUsageState = (ApiUsageState) event.getEntity();
 | 
					                ApiUsageState apiUsageState = (ApiUsageState) event.getEntity();
 | 
				
			||||||
                tbClusterService.onApiStateChange(apiUsageState, null);
 | 
					                tbClusterService.onApiStateChange(apiUsageState, null);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            default -> {}
 | 
					            case CALCULATED_FIELD -> {
 | 
				
			||||||
 | 
					                onCalculatedFieldUpdate(event.getEntity(), event.getOldEntity());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            default -> {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -149,7 +154,8 @@ public class EntityStateSourcingListener {
 | 
				
			|||||||
            case RULE_CHAIN -> {
 | 
					            case RULE_CHAIN -> {
 | 
				
			||||||
                RuleChain ruleChain = (RuleChain) event.getEntity();
 | 
					                RuleChain ruleChain = (RuleChain) event.getEntity();
 | 
				
			||||||
                if (RuleChainType.CORE.equals(ruleChain.getType())) {
 | 
					                if (RuleChainType.CORE.equals(ruleChain.getType())) {
 | 
				
			||||||
                    Set<RuleChainId> referencingRuleChainIds = JacksonUtil.fromString(event.getBody(), new TypeReference<>() {});
 | 
					                    Set<RuleChainId> referencingRuleChainIds = JacksonUtil.fromString(event.getBody(), new TypeReference<>() {
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
                    if (referencingRuleChainIds != null) {
 | 
					                    if (referencingRuleChainIds != null) {
 | 
				
			||||||
                        referencingRuleChainIds.forEach(referencingRuleChainId ->
 | 
					                        referencingRuleChainIds.forEach(referencingRuleChainId ->
 | 
				
			||||||
                                tbClusterService.broadcastEntityStateChangeEvent(tenantId, referencingRuleChainId, ComponentLifecycleEvent.UPDATED));
 | 
					                                tbClusterService.broadcastEntityStateChangeEvent(tenantId, referencingRuleChainId, ComponentLifecycleEvent.UPDATED));
 | 
				
			||||||
@ -177,7 +183,12 @@ public class EntityStateSourcingListener {
 | 
				
			|||||||
                TbResourceInfo tbResource = (TbResourceInfo) event.getEntity();
 | 
					                TbResourceInfo tbResource = (TbResourceInfo) event.getEntity();
 | 
				
			||||||
                tbClusterService.onResourceDeleted(tbResource, null);
 | 
					                tbClusterService.onResourceDeleted(tbResource, null);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            default -> {}
 | 
					            case CALCULATED_FIELD -> {
 | 
				
			||||||
 | 
					                CalculatedField calculatedField = (CalculatedField) event.getEntity();
 | 
				
			||||||
 | 
					                tbClusterService.onCalculatedFieldDeleted(tenantId, calculatedField, null);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            default -> {
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -247,6 +258,15 @@ public class EntityStateSourcingListener {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void onCalculatedFieldUpdate(Object entity, Object oldEntity) {
 | 
				
			||||||
 | 
					        CalculatedField calculatedField = (CalculatedField) entity;
 | 
				
			||||||
 | 
					        CalculatedField oldCalculatedField = null;
 | 
				
			||||||
 | 
					        if (oldEntity instanceof CalculatedField) {
 | 
				
			||||||
 | 
					            oldCalculatedField = (CalculatedField) oldEntity;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        tbClusterService.onCalculatedFieldUpdated(calculatedField, oldCalculatedField);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
 | 
					    private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
 | 
				
			||||||
        String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
 | 
					        String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
 | 
				
			||||||
        if (data != null) {
 | 
					        if (data != null) {
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
 | 
				
			|||||||
import org.springframework.beans.factory.annotation.Value;
 | 
					import org.springframework.beans.factory.annotation.Value;
 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
import org.springframework.transaction.annotation.Transactional;
 | 
					import org.springframework.transaction.annotation.Transactional;
 | 
				
			||||||
 | 
					import org.thingsboard.common.util.JacksonUtil;
 | 
				
			||||||
import org.thingsboard.common.util.ThingsBoardExecutors;
 | 
					import org.thingsboard.common.util.ThingsBoardExecutors;
 | 
				
			||||||
import org.thingsboard.common.util.ThingsBoardThreadFactory;
 | 
					import org.thingsboard.common.util.ThingsBoardThreadFactory;
 | 
				
			||||||
import org.thingsboard.server.common.data.AttributeScope;
 | 
					import org.thingsboard.server.common.data.AttributeScope;
 | 
				
			||||||
@ -64,6 +65,7 @@ import java.util.ArrayList;
 | 
				
			|||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
import java.util.Random;
 | 
					import java.util.Random;
 | 
				
			||||||
import java.util.UUID;
 | 
					import java.util.UUID;
 | 
				
			||||||
@ -71,6 +73,7 @@ import java.util.concurrent.ConcurrentHashMap;
 | 
				
			|||||||
import java.util.concurrent.ConcurrentMap;
 | 
					import java.util.concurrent.ConcurrentMap;
 | 
				
			||||||
import java.util.concurrent.Executors;
 | 
					import java.util.concurrent.Executors;
 | 
				
			||||||
import java.util.concurrent.TimeUnit;
 | 
					import java.util.concurrent.TimeUnit;
 | 
				
			||||||
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.thingsboard.server.dao.service.Validator.validateEntityId;
 | 
					import static org.thingsboard.server.dao.service.Validator.validateEntityId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -83,6 +86,7 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
 | 
				
			|||||||
    private final CalculatedFieldService calculatedFieldService;
 | 
					    private final CalculatedFieldService calculatedFieldService;
 | 
				
			||||||
    private final AttributesService attributesService;
 | 
					    private final AttributesService attributesService;
 | 
				
			||||||
    private final TimeseriesService timeseriesService;
 | 
					    private final TimeseriesService timeseriesService;
 | 
				
			||||||
 | 
					    private final RocksDBService rocksDBService;
 | 
				
			||||||
    private ListeningScheduledExecutorService scheduledExecutor;
 | 
					    private ListeningScheduledExecutorService scheduledExecutor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ListeningExecutorService calculatedFieldExecutor;
 | 
					    private ListeningExecutorService calculatedFieldExecutor;
 | 
				
			||||||
@ -212,6 +216,10 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
 | 
				
			|||||||
            calculatedFieldLinks.remove(calculatedFieldId);
 | 
					            calculatedFieldLinks.remove(calculatedFieldId);
 | 
				
			||||||
            calculatedFields.remove(calculatedFieldId);
 | 
					            calculatedFields.remove(calculatedFieldId);
 | 
				
			||||||
            states.keySet().removeIf(ctxId -> ctxId.startsWith(calculatedFieldId.getId().toString()));
 | 
					            states.keySet().removeIf(ctxId -> ctxId.startsWith(calculatedFieldId.getId().toString()));
 | 
				
			||||||
 | 
					            List<String> statesToRemove = states.keySet().stream()
 | 
				
			||||||
 | 
					                    .filter(key -> key.startsWith(calculatedFieldId.getId().toString()))
 | 
				
			||||||
 | 
					                    .collect(Collectors.toList());
 | 
				
			||||||
 | 
					            rocksDBService.deleteAll(statesToRemove);
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            log.trace("Failed to delete calculated field.", e);
 | 
					            log.trace("Failed to delete calculated field.", e);
 | 
				
			||||||
            callback.onFailure(e);
 | 
					            callback.onFailure(e);
 | 
				
			||||||
@ -223,7 +231,7 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
 | 
				
			|||||||
        cfs.forEach(cf -> calculatedFields.putIfAbsent(cf.getId(), cf));
 | 
					        cfs.forEach(cf -> calculatedFields.putIfAbsent(cf.getId(), cf));
 | 
				
			||||||
        PageDataIterable<CalculatedFieldLink> cfls = new PageDataIterable<>(calculatedFieldService::findAllCalculatedFieldLinks, initFetchPackSize);
 | 
					        PageDataIterable<CalculatedFieldLink> cfls = new PageDataIterable<>(calculatedFieldService::findAllCalculatedFieldLinks, initFetchPackSize);
 | 
				
			||||||
        cfls.forEach(link -> calculatedFieldLinks.computeIfAbsent(link.getCalculatedFieldId(), id -> new ArrayList<>()).add(link));
 | 
					        cfls.forEach(link -> calculatedFieldLinks.computeIfAbsent(link.getCalculatedFieldId(), id -> new ArrayList<>()).add(link));
 | 
				
			||||||
        // TODO:    read all states(CalculatedFieldCtx)
 | 
					        rocksDBService.getAll().forEach((ctxId, ctx) -> states.put(ctxId, JacksonUtil.convertValue(ctx, CalculatedFieldCtx.class)));
 | 
				
			||||||
        states.keySet().removeIf(ctxId -> calculatedFields.keySet().stream().noneMatch(id -> ctxId.startsWith(id.toString())));
 | 
					        states.keySet().removeIf(ctxId -> calculatedFields.keySet().stream().noneMatch(id -> ctxId.startsWith(id.toString())));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -319,6 +327,7 @@ public class DefaultTbCalculatedFieldService extends AbstractTbEntityService imp
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        calculatedFieldCtx.setState(state);
 | 
					        calculatedFieldCtx.setState(state);
 | 
				
			||||||
        states.put(ctxId, calculatedFieldCtx);
 | 
					        states.put(ctxId, calculatedFieldCtx);
 | 
				
			||||||
 | 
					        rocksDBService.put(ctxId, Objects.requireNonNull(JacksonUtil.toString(calculatedFieldCtx)));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private String performCalculation(Map<String, String> argumentValues, CalculatedFieldConfiguration calculatedFieldConfiguration) {
 | 
					    private String performCalculation(Map<String, String> argumentValues, CalculatedFieldConfiguration calculatedFieldConfiguration) {
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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.rocksdb.RocksDB;
 | 
				
			||||||
 | 
					import org.rocksdb.RocksDBException;
 | 
				
			||||||
 | 
					import org.rocksdb.RocksIterator;
 | 
				
			||||||
 | 
					import org.rocksdb.WriteBatch;
 | 
				
			||||||
 | 
					import org.rocksdb.WriteOptions;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
 | 
					import org.thingsboard.server.utils.RocksDBConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Service
 | 
				
			||||||
 | 
					@Slf4j
 | 
				
			||||||
 | 
					public class RocksDBService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final RocksDB db;
 | 
				
			||||||
 | 
					    private final WriteOptions writeOptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public RocksDBService(RocksDBConfig config) throws RocksDBException {
 | 
				
			||||||
 | 
					        this.db = config.getDb();
 | 
				
			||||||
 | 
					        this.writeOptions = new WriteOptions().setSync(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void put(String key, String value) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            db.put(writeOptions, key.getBytes(StandardCharsets.UTF_8), value.getBytes(StandardCharsets.UTF_8));
 | 
				
			||||||
 | 
					        } catch (RocksDBException e) {
 | 
				
			||||||
 | 
					            log.error("Failed to store data to RocksDB", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void delete(String key) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            db.delete(writeOptions, key.getBytes(StandardCharsets.UTF_8));
 | 
				
			||||||
 | 
					        } catch (RocksDBException e) {
 | 
				
			||||||
 | 
					            log.error("Failed to delete data from RocksDB", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void deleteAll(List<String> keys) {
 | 
				
			||||||
 | 
					        try (WriteBatch batch = new WriteBatch()) {
 | 
				
			||||||
 | 
					            for (String key : keys) {
 | 
				
			||||||
 | 
					                batch.delete(key.getBytes(StandardCharsets.UTF_8));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            db.write(writeOptions, batch);
 | 
				
			||||||
 | 
					        } catch (RocksDBException e) {
 | 
				
			||||||
 | 
					            log.error("Failed to delete data from RocksDB", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String get(String key) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            byte[] value = db.get(key.getBytes(StandardCharsets.UTF_8));
 | 
				
			||||||
 | 
					            return value != null ? new String(value, StandardCharsets.UTF_8) : null;
 | 
				
			||||||
 | 
					        } catch (RocksDBException e) {
 | 
				
			||||||
 | 
					            log.error("Failed to retrieve data from RocksDB", e);
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public Map<String, String> getAll() {
 | 
				
			||||||
 | 
					        Map<String, String> map = new HashMap<>();
 | 
				
			||||||
 | 
					        try (RocksIterator iterator = db.newIterator()) {
 | 
				
			||||||
 | 
					            for (iterator.seekToFirst(); iterator.isValid(); iterator.next()) {
 | 
				
			||||||
 | 
					                String key = new String(iterator.key(), StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                String value = new String(iterator.value(), StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                map.put(key, value);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            log.error("Failed to retrieve data from RocksDB", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return map;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -38,10 +38,12 @@ import org.thingsboard.server.common.data.TbResourceInfo;
 | 
				
			|||||||
import org.thingsboard.server.common.data.Tenant;
 | 
					import org.thingsboard.server.common.data.Tenant;
 | 
				
			||||||
import org.thingsboard.server.common.data.TenantProfile;
 | 
					import org.thingsboard.server.common.data.TenantProfile;
 | 
				
			||||||
import org.thingsboard.server.common.data.asset.Asset;
 | 
					import org.thingsboard.server.common.data.asset.Asset;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
				
			||||||
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
 | 
					import org.thingsboard.server.common.data.edge.EdgeEventActionType;
 | 
				
			||||||
import org.thingsboard.server.common.data.edge.EdgeEventType;
 | 
					import org.thingsboard.server.common.data.edge.EdgeEventType;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.AssetId;
 | 
					import org.thingsboard.server.common.data.id.AssetId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.AssetProfileId;
 | 
					import org.thingsboard.server.common.data.id.AssetProfileId;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.id.CalculatedFieldId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
					import org.thingsboard.server.common.data.id.DeviceId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
 | 
					import org.thingsboard.server.common.data.id.DeviceProfileId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.EdgeId;
 | 
					import org.thingsboard.server.common.data.id.EdgeId;
 | 
				
			||||||
@ -666,7 +668,8 @@ public class DefaultTbClusterService implements TbClusterService {
 | 
				
			|||||||
    private void pushDeviceUpdateMessage(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) {
 | 
					    private void pushDeviceUpdateMessage(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) {
 | 
				
			||||||
        log.trace("{} Going to send edge update notification for device actor, device id {}, edge id {}", tenantId, entityId, edgeId);
 | 
					        log.trace("{} Going to send edge update notification for device actor, device id {}, edge id {}", tenantId, entityId, edgeId);
 | 
				
			||||||
        switch (action) {
 | 
					        switch (action) {
 | 
				
			||||||
            case ASSIGNED_TO_EDGE -> pushMsgToCore(new DeviceEdgeUpdateMsg(tenantId, new DeviceId(entityId.getId()), edgeId), null);
 | 
					            case ASSIGNED_TO_EDGE ->
 | 
				
			||||||
 | 
					                    pushMsgToCore(new DeviceEdgeUpdateMsg(tenantId, new DeviceId(entityId.getId()), edgeId), null);
 | 
				
			||||||
            case UNASSIGNED_FROM_EDGE -> {
 | 
					            case UNASSIGNED_FROM_EDGE -> {
 | 
				
			||||||
                EdgeId relatedEdgeId = findRelatedEdgeIdIfAny(tenantId, entityId);
 | 
					                EdgeId relatedEdgeId = findRelatedEdgeIdIfAny(tenantId, entityId);
 | 
				
			||||||
                pushMsgToCore(new DeviceEdgeUpdateMsg(tenantId, new DeviceId(entityId.getId()), relatedEdgeId), null);
 | 
					                pushMsgToCore(new DeviceEdgeUpdateMsg(tenantId, new DeviceId(entityId.getId()), relatedEdgeId), null);
 | 
				
			||||||
@ -743,4 +746,33 @@ public class DefaultTbClusterService implements TbClusterService {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onCalculatedFieldUpdated(CalculatedField calculatedField, CalculatedField oldCalculatedField) {
 | 
				
			||||||
 | 
					        var created = oldCalculatedField == null;
 | 
				
			||||||
 | 
					        broadcastEntityChangeToTransport(calculatedField.getTenantId(), calculatedField.getId(), calculatedField, null);
 | 
				
			||||||
 | 
					        broadcastEntityStateChangeEvent(calculatedField.getTenantId(), calculatedField.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
 | 
				
			||||||
 | 
					        sendCalculatedFieldEvent(calculatedField.getTenantId(), calculatedField.getId(), created, !created, false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onCalculatedFieldDeleted(TenantId tenantId, CalculatedField calculatedField, TbQueueCallback callback) {
 | 
				
			||||||
 | 
					        CalculatedFieldId calculatedFieldId = calculatedField.getId();
 | 
				
			||||||
 | 
					        broadcastEntityDeleteToTransport(tenantId, calculatedFieldId, calculatedField.getName(), callback);
 | 
				
			||||||
 | 
					        sendCalculatedFieldEvent(tenantId, calculatedFieldId, false, false, true);
 | 
				
			||||||
 | 
					        broadcastEntityStateChangeEvent(tenantId, calculatedFieldId, ComponentLifecycleEvent.DELETED);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void sendCalculatedFieldEvent(TenantId tenantId, CalculatedFieldId calculatedFieldId, boolean added, boolean updated, boolean deleted) {
 | 
				
			||||||
 | 
					        TransportProtos.CalculatedFieldMsgProto.Builder builder = TransportProtos.CalculatedFieldMsgProto.newBuilder();
 | 
				
			||||||
 | 
					        builder.setTenantIdMSB(tenantId.getId().getMostSignificantBits());
 | 
				
			||||||
 | 
					        builder.setTenantIdLSB(tenantId.getId().getLeastSignificantBits());
 | 
				
			||||||
 | 
					        builder.setCalculatedFieldIdMSB(calculatedFieldId.getId().getMostSignificantBits());
 | 
				
			||||||
 | 
					        builder.setCalculatedFieldIdLSB(calculatedFieldId.getId().getLeastSignificantBits());
 | 
				
			||||||
 | 
					        builder.setAdded(added);
 | 
				
			||||||
 | 
					        builder.setUpdated(updated);
 | 
				
			||||||
 | 
					        builder.setDeleted(deleted);
 | 
				
			||||||
 | 
					        TransportProtos.CalculatedFieldMsgProto msg = builder.build();
 | 
				
			||||||
 | 
					        pushMsgToCore(tenantId, calculatedFieldId, ToCoreMsg.newBuilder().setCalculatedFieldMsg(msg).build(), null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
 | 
				
			|||||||
import org.thingsboard.server.common.data.event.ErrorEvent;
 | 
					import org.thingsboard.server.common.data.event.ErrorEvent;
 | 
				
			||||||
import org.thingsboard.server.common.data.event.Event;
 | 
					import org.thingsboard.server.common.data.event.Event;
 | 
				
			||||||
import org.thingsboard.server.common.data.event.LifecycleEvent;
 | 
					import org.thingsboard.server.common.data.event.LifecycleEvent;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.id.CalculatedFieldId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
					import org.thingsboard.server.common.data.id.DeviceId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.NotificationRequestId;
 | 
					import org.thingsboard.server.common.data.id.NotificationRequestId;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			||||||
@ -85,6 +86,7 @@ import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
 | 
				
			|||||||
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
 | 
					import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
 | 
				
			||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
 | 
					import org.thingsboard.server.queue.util.TbCoreComponent;
 | 
				
			||||||
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
 | 
					import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
 | 
				
			||||||
 | 
					import org.thingsboard.server.service.entitiy.cf.TbCalculatedFieldService;
 | 
				
			||||||
import org.thingsboard.server.service.notification.NotificationSchedulerService;
 | 
					import org.thingsboard.server.service.notification.NotificationSchedulerService;
 | 
				
			||||||
import org.thingsboard.server.service.ota.OtaPackageStateService;
 | 
					import org.thingsboard.server.service.ota.OtaPackageStateService;
 | 
				
			||||||
import org.thingsboard.server.service.profile.TbAssetProfileCache;
 | 
					import org.thingsboard.server.service.profile.TbAssetProfileCache;
 | 
				
			||||||
@ -148,6 +150,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
 | 
				
			|||||||
    private final TbImageService imageService;
 | 
					    private final TbImageService imageService;
 | 
				
			||||||
    private final RuleEngineCallService ruleEngineCallService;
 | 
					    private final RuleEngineCallService ruleEngineCallService;
 | 
				
			||||||
    private final TbCoreConsumerStats stats;
 | 
					    private final TbCoreConsumerStats stats;
 | 
				
			||||||
 | 
					    private final TbCalculatedFieldService calculatedFieldService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private MainQueueConsumerManager<TbProtoQueueMsg<ToCoreMsg>, CoreQueueConfig> mainConsumer;
 | 
					    private MainQueueConsumerManager<TbProtoQueueMsg<ToCoreMsg>, CoreQueueConfig> mainConsumer;
 | 
				
			||||||
    private QueueConsumerManager<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer;
 | 
					    private QueueConsumerManager<TbProtoQueueMsg<ToUsageStatsServiceMsg>> usageStatsConsumer;
 | 
				
			||||||
@ -175,7 +178,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
 | 
				
			|||||||
                                        NotificationSchedulerService notificationSchedulerService,
 | 
					                                        NotificationSchedulerService notificationSchedulerService,
 | 
				
			||||||
                                        NotificationRuleProcessor notificationRuleProcessor,
 | 
					                                        NotificationRuleProcessor notificationRuleProcessor,
 | 
				
			||||||
                                        TbImageService imageService,
 | 
					                                        TbImageService imageService,
 | 
				
			||||||
                                        RuleEngineCallService ruleEngineCallService) {
 | 
					                                        RuleEngineCallService ruleEngineCallService,
 | 
				
			||||||
 | 
					                                        TbCalculatedFieldService calculatedFieldService) {
 | 
				
			||||||
        super(actorContext, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService,
 | 
					        super(actorContext, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService,
 | 
				
			||||||
                eventPublisher, jwtSettingsService);
 | 
					                eventPublisher, jwtSettingsService);
 | 
				
			||||||
        this.stateService = stateService;
 | 
					        this.stateService = stateService;
 | 
				
			||||||
@ -191,6 +195,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
 | 
				
			|||||||
        this.imageService = imageService;
 | 
					        this.imageService = imageService;
 | 
				
			||||||
        this.ruleEngineCallService = ruleEngineCallService;
 | 
					        this.ruleEngineCallService = ruleEngineCallService;
 | 
				
			||||||
        this.queueFactory = tbCoreQueueFactory;
 | 
					        this.queueFactory = tbCoreQueueFactory;
 | 
				
			||||||
 | 
					        this.calculatedFieldService = calculatedFieldService;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @PostConstruct
 | 
					    @PostConstruct
 | 
				
			||||||
@ -308,6 +313,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
 | 
				
			|||||||
                        forwardToEventService(toCoreMsg.getErrorEventMsg(), callback);
 | 
					                        forwardToEventService(toCoreMsg.getErrorEventMsg(), callback);
 | 
				
			||||||
                    } else if (toCoreMsg.hasLifecycleEventMsg()) {
 | 
					                    } else if (toCoreMsg.hasLifecycleEventMsg()) {
 | 
				
			||||||
                        forwardToEventService(toCoreMsg.getLifecycleEventMsg(), callback);
 | 
					                        forwardToEventService(toCoreMsg.getLifecycleEventMsg(), callback);
 | 
				
			||||||
 | 
					                    } else if (toCoreMsg.hasCalculatedFieldMsg()) {
 | 
				
			||||||
 | 
					                        forwardToCalculatedFieldService(toCoreMsg.getCalculatedFieldMsg(), callback);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } catch (Throwable e) {
 | 
					                } catch (Throwable e) {
 | 
				
			||||||
                    log.warn("[{}] Failed to process message: {}", id, msg, e);
 | 
					                    log.warn("[{}] Failed to process message: {}", id, msg, e);
 | 
				
			||||||
@ -658,6 +665,18 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
 | 
				
			|||||||
                });
 | 
					                });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void forwardToCalculatedFieldService(TransportProtos.CalculatedFieldMsgProto calculatedFieldMsg, TbCallback callback) {
 | 
				
			||||||
 | 
					        var tenantId = toTenantId(calculatedFieldMsg.getTenantIdMSB(), calculatedFieldMsg.getTenantIdLSB());
 | 
				
			||||||
 | 
					        var calculatedFieldId = new CalculatedFieldId(new UUID(calculatedFieldMsg.getCalculatedFieldIdMSB(), calculatedFieldMsg.getCalculatedFieldIdLSB()));
 | 
				
			||||||
 | 
					        ListenableFuture<?> future = deviceActivityEventsExecutor.submit(() -> calculatedFieldService.onCalculatedFieldMsg(calculatedFieldMsg, callback));
 | 
				
			||||||
 | 
					        DonAsynchron.withCallback(future,
 | 
				
			||||||
 | 
					                __ -> callback.onSuccess(),
 | 
				
			||||||
 | 
					                t -> {
 | 
				
			||||||
 | 
					                    log.warn("[{}] Failed to process calculated field message for calculated field [{}]", tenantId.getId(), calculatedFieldId.getId(), t);
 | 
				
			||||||
 | 
					                    callback.onFailure(t);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void forwardToNotificationSchedulerService(TransportProtos.NotificationSchedulerServiceMsg msg, TbCallback callback) {
 | 
					    private void forwardToNotificationSchedulerService(TransportProtos.NotificationSchedulerServiceMsg msg, TbCallback callback) {
 | 
				
			||||||
        TenantId tenantId = toTenantId(msg.getTenantIdMSB(), msg.getTenantIdLSB());
 | 
					        TenantId tenantId = toTenantId(msg.getTenantIdMSB(), msg.getTenantIdLSB());
 | 
				
			||||||
        NotificationRequestId notificationRequestId = new NotificationRequestId(new UUID(msg.getRequestIdMSB(), msg.getRequestIdLSB()));
 | 
					        NotificationRequestId notificationRequestId = new NotificationRequestId(new UUID(msg.getRequestIdMSB(), msg.getRequestIdLSB()));
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jakarta.annotation.PreDestroy;
 | 
				
			||||||
 | 
					import org.rocksdb.Options;
 | 
				
			||||||
 | 
					import org.rocksdb.RocksDB;
 | 
				
			||||||
 | 
					import org.rocksdb.RocksDBException;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.annotation.Value;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component
 | 
				
			||||||
 | 
					public class RocksDBConfig {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Value("${rocksdb.db_path}")
 | 
				
			||||||
 | 
					    private String dbPath;
 | 
				
			||||||
 | 
					    private RocksDB db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static {
 | 
				
			||||||
 | 
					        RocksDB.loadLibrary();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public RocksDB getDb() throws RocksDBException {
 | 
				
			||||||
 | 
					        if (db == null) {
 | 
				
			||||||
 | 
					            Options options = new Options().setCreateIfMissing(true);
 | 
				
			||||||
 | 
					            db = RocksDB.open(options, dbPath);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return db;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @PreDestroy
 | 
				
			||||||
 | 
					    public void close() {
 | 
				
			||||||
 | 
					        if (db != null) {
 | 
				
			||||||
 | 
					            db.close();
 | 
				
			||||||
 | 
					            db = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -424,6 +424,10 @@ sql:
 | 
				
			|||||||
    pool_size: "${SQL_RELATIONS_POOL_SIZE:4}" # This value has to be reasonably small to prevent the relation query from blocking all other DB calls
 | 
					    pool_size: "${SQL_RELATIONS_POOL_SIZE:4}" # This value has to be reasonably small to prevent the relation query from blocking all other DB calls
 | 
				
			||||||
    query_timeout: "${SQL_RELATIONS_QUERY_TIMEOUT_SEC:20}" # This value has to be reasonably small to prevent the relation query from blocking all other DB calls
 | 
					    query_timeout: "${SQL_RELATIONS_QUERY_TIMEOUT_SEC:20}" # This value has to be reasonably small to prevent the relation query from blocking all other DB calls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rocksdb:
 | 
				
			||||||
 | 
					  # Rocksdb path
 | 
				
			||||||
 | 
					  db_path: "${ROCKS_DB_PATH:}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Actor system parameters
 | 
					# Actor system parameters
 | 
				
			||||||
actors:
 | 
					actors:
 | 
				
			||||||
  system:
 | 
					  system:
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.DeviceProfile;
 | 
				
			|||||||
import org.thingsboard.server.common.data.TbResourceInfo;
 | 
					import org.thingsboard.server.common.data.TbResourceInfo;
 | 
				
			||||||
import org.thingsboard.server.common.data.Tenant;
 | 
					import org.thingsboard.server.common.data.Tenant;
 | 
				
			||||||
import org.thingsboard.server.common.data.TenantProfile;
 | 
					import org.thingsboard.server.common.data.TenantProfile;
 | 
				
			||||||
 | 
					import org.thingsboard.server.common.data.cf.CalculatedField;
 | 
				
			||||||
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
 | 
					import org.thingsboard.server.common.data.edge.EdgeEventActionType;
 | 
				
			||||||
import org.thingsboard.server.common.data.edge.EdgeEventType;
 | 
					import org.thingsboard.server.common.data.edge.EdgeEventType;
 | 
				
			||||||
import org.thingsboard.server.common.data.id.EdgeId;
 | 
					import org.thingsboard.server.common.data.id.EdgeId;
 | 
				
			||||||
@ -114,4 +115,8 @@ public interface TbClusterService extends TbQueueClusterService {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action, EdgeId sourceEdgeId);
 | 
					    void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action, EdgeId sourceEdgeId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void onCalculatedFieldUpdated(CalculatedField calculatedField, CalculatedField oldCalculatedField);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void onCalculatedFieldDeleted(TenantId tenantId, CalculatedField calculatedField, TbQueueCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1512,6 +1512,7 @@ message ToCoreMsg {
 | 
				
			|||||||
  DeviceConnectProto deviceConnectMsg = 50;
 | 
					  DeviceConnectProto deviceConnectMsg = 50;
 | 
				
			||||||
  DeviceDisconnectProto deviceDisconnectMsg = 51;
 | 
					  DeviceDisconnectProto deviceDisconnectMsg = 51;
 | 
				
			||||||
  DeviceInactivityProto deviceInactivityMsg = 52;
 | 
					  DeviceInactivityProto deviceInactivityMsg = 52;
 | 
				
			||||||
 | 
					  CalculatedFieldMsgProto calculatedFieldMsg = 53;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* High priority messages with low latency are handled by ThingsBoard Core Service separately */
 | 
					/* High priority messages with low latency are handled by ThingsBoard Core Service separately */
 | 
				
			||||||
 | 
				
			|||||||
@ -29,20 +29,21 @@ import org.thingsboard.server.common.data.id.HasId;
 | 
				
			|||||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
					import org.thingsboard.server.common.data.id.TenantId;
 | 
				
			||||||
import org.thingsboard.server.common.data.page.PageData;
 | 
					import org.thingsboard.server.common.data.page.PageData;
 | 
				
			||||||
import org.thingsboard.server.common.data.page.PageLink;
 | 
					import org.thingsboard.server.common.data.page.PageLink;
 | 
				
			||||||
 | 
					import org.thingsboard.server.dao.entity.AbstractEntityService;
 | 
				
			||||||
 | 
					import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
 | 
				
			||||||
import org.thingsboard.server.dao.service.DataValidator;
 | 
					import org.thingsboard.server.dao.service.DataValidator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Optional;
 | 
					import java.util.Optional;
 | 
				
			||||||
import java.util.stream.Collectors;
 | 
					import java.util.stream.Collectors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.thingsboard.server.dao.entity.AbstractEntityService.checkConstraintViolation;
 | 
					 | 
				
			||||||
import static org.thingsboard.server.dao.service.Validator.validateId;
 | 
					import static org.thingsboard.server.dao.service.Validator.validateId;
 | 
				
			||||||
import static org.thingsboard.server.dao.service.Validator.validatePageLink;
 | 
					import static org.thingsboard.server.dao.service.Validator.validatePageLink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Service("CalculatedFieldDaoService")
 | 
					@Service("CalculatedFieldDaoService")
 | 
				
			||||||
@Slf4j
 | 
					@Slf4j
 | 
				
			||||||
@RequiredArgsConstructor
 | 
					@RequiredArgsConstructor
 | 
				
			||||||
public class BaseCalculatedFieldService implements CalculatedFieldService {
 | 
					public class BaseCalculatedFieldService extends AbstractEntityService implements CalculatedFieldService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
 | 
					    public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
 | 
				
			||||||
    public static final String INCORRECT_CALCULATED_FIELD_ID = "Incorrect calculatedFieldId ";
 | 
					    public static final String INCORRECT_CALCULATED_FIELD_ID = "Incorrect calculatedFieldId ";
 | 
				
			||||||
@ -60,6 +61,8 @@ public class BaseCalculatedFieldService implements CalculatedFieldService {
 | 
				
			|||||||
            log.trace("Executing save calculated field, [{}]", calculatedField);
 | 
					            log.trace("Executing save calculated field, [{}]", calculatedField);
 | 
				
			||||||
            CalculatedField savedCalculatedField = calculatedFieldDao.save(tenantId, calculatedField);
 | 
					            CalculatedField savedCalculatedField = calculatedFieldDao.save(tenantId, calculatedField);
 | 
				
			||||||
            createOrUpdateCalculatedFieldLink(tenantId, savedCalculatedField);
 | 
					            createOrUpdateCalculatedFieldLink(tenantId, savedCalculatedField);
 | 
				
			||||||
 | 
					            eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedCalculatedField.getTenantId()).entityId(savedCalculatedField.getId())
 | 
				
			||||||
 | 
					                    .entity(savedCalculatedField).created(calculatedField.getId() == null).build());
 | 
				
			||||||
            return savedCalculatedField;
 | 
					            return savedCalculatedField;
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            checkConstraintViolation(e,
 | 
					            checkConstraintViolation(e,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								pom.xml
									
									
									
									
									
								
							@ -166,6 +166,8 @@
 | 
				
			|||||||
        <weisj-jsvg.version>1.6.1</weisj-jsvg.version>
 | 
					        <weisj-jsvg.version>1.6.1</weisj-jsvg.version>
 | 
				
			||||||
        <drewnoakes-metadata-extractor.version>2.19.0</drewnoakes-metadata-extractor.version>
 | 
					        <drewnoakes-metadata-extractor.version>2.19.0</drewnoakes-metadata-extractor.version>
 | 
				
			||||||
        <firebase-admin.version>9.2.0</firebase-admin.version>
 | 
					        <firebase-admin.version>9.2.0</firebase-admin.version>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <rocksdbjni.version>9.4.0</rocksdbjni.version>
 | 
				
			||||||
    </properties>
 | 
					    </properties>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <modules>
 | 
					    <modules>
 | 
				
			||||||
@ -2272,6 +2274,11 @@
 | 
				
			|||||||
                <artifactId>metadata-extractor</artifactId>
 | 
					                <artifactId>metadata-extractor</artifactId>
 | 
				
			||||||
                <version>${drewnoakes-metadata-extractor.version}</version>
 | 
					                <version>${drewnoakes-metadata-extractor.version}</version>
 | 
				
			||||||
            </dependency>
 | 
					            </dependency>
 | 
				
			||||||
 | 
					            <dependency>
 | 
				
			||||||
 | 
					                <groupId>org.rocksdb</groupId>
 | 
				
			||||||
 | 
					                <artifactId>rocksdbjni</artifactId>
 | 
				
			||||||
 | 
					                <version>${rocksdbjni.version}</version>
 | 
				
			||||||
 | 
					            </dependency>
 | 
				
			||||||
        </dependencies>
 | 
					        </dependencies>
 | 
				
			||||||
    </dependencyManagement>
 | 
					    </dependencyManagement>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user