added admin setting fetcher

This commit is contained in:
Volodymyr Babak 2021-05-20 13:05:21 +03:00
parent c43bc3c8b1
commit 2c826c12cd
14 changed files with 115 additions and 86 deletions

View File

@ -635,7 +635,7 @@ public class RuleChainController extends BaseController {
} }
} }
// TODO: refactor this - add new config to edge rule chain to set it as auto-assign // TODO: @voba refactor this - add new config to edge rule chain to set it as auto-assign
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET) @RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET)
@ResponseBody @ResponseBody

View File

@ -27,6 +27,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -62,6 +63,10 @@ public class EdgeContextComponent {
@Autowired @Autowired
private EdgeEventService edgeEventService; private EdgeEventService edgeEventService;
@Lazy
@Autowired
private AdminSettingsService adminSettingsService;
@Lazy @Lazy
@Autowired @Autowired
private AssetService assetService; private AssetService assetService;

View File

@ -68,6 +68,7 @@ import org.thingsboard.server.gen.edge.UplinkResponseMsg;
import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg; import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.WidgetBundleTypesRequestMsg; import org.thingsboard.server.gen.edge.WidgetBundleTypesRequestMsg;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.EdgeContextComponent;
import org.thingsboard.server.service.edge.rpc.fetch.AdminSettingsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher;
import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher;
@ -207,8 +208,7 @@ public final class EdgeGrpcSession implements Closeable {
startProcessingEdgeEvents(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId())); startProcessingEdgeEvents(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId()));
} }
// TODO: voba - implement this functionality startProcessingEdgeEvents(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService()));
// syncAdminSettings(edge);
startProcessingEdgeEvents(new AssetsEdgeEventFetcher(ctx.getAssetService())); startProcessingEdgeEvents(new AssetsEdgeEventFetcher(ctx.getAssetService()));
startProcessingEdgeEvents(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); startProcessingEdgeEvents(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
@ -285,7 +285,7 @@ public final class EdgeGrpcSession implements Closeable {
sendDownlinkMsg(edgeConfigMsg); sendDownlinkMsg(edgeConfigMsg);
} }
void processEdgeEvents() throws ExecutionException, InterruptedException { void processEdgeEvents() throws Exception {
log.trace("[{}] processHandleMessages started", this.sessionId); log.trace("[{}] processHandleMessages started", this.sessionId);
if (isConnected() && isSyncCompleted()) { if (isConnected() && isSyncCompleted()) {
Long queueStartTs = getQueueStartTs().get(); Long queueStartTs = getQueueStartTs().get();
@ -301,7 +301,7 @@ public final class EdgeGrpcSession implements Closeable {
log.trace("[{}] processHandleMessages finished", this.sessionId); log.trace("[{}] processHandleMessages finished", this.sessionId);
} }
private UUID startProcessingEdgeEvents(EdgeEventFetcher fetcher) throws InterruptedException { private UUID startProcessingEdgeEvents(EdgeEventFetcher fetcher) throws Exception {
PageLink pageLink = fetcher.getPageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount()); PageLink pageLink = fetcher.getPageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount());
PageData<EdgeEvent> pageData; PageData<EdgeEvent> pageData;
UUID ifOffset = null; UUID ifOffset = null;

View File

@ -41,7 +41,7 @@ public class DeviceProfileMsgConstructor {
.setDefault(deviceProfile.isDefault()) .setDefault(deviceProfile.isDefault())
.setType(deviceProfile.getType().name()) .setType(deviceProfile.getType().name())
.setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile.getProfileData()))); .setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile.getProfileData())));
// TODO: voba - should this be always null at the moment?? // TODO: @voba - add possibility to setup edge rule chain as device profile default
// if (deviceProfile.getDefaultRuleChainId() != null) { // if (deviceProfile.getDefaultRuleChainId() != null) {
// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits()) // builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits()); // .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());

View File

@ -15,90 +15,115 @@
*/ */
package org.thingsboard.server.service.edge.rpc.fetch; package org.thingsboard.server.service.edge.rpc.fetch;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.AdminSettingsId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
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.settings.AdminSettingsService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
public class AdminSettingsEdgeEventFetcher extends BasePageableEdgeEventFetcher { public class AdminSettingsEdgeEventFetcher extends BasePageableEdgeEventFetcher {
private final AdminSettingsService adminSettingsService;
@Override @Override
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) { public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) throws Exception {
return null; List<EdgeEvent> result = new ArrayList<>();
AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)));
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)));
AdminSettings systemMailTemplates = loadMailTemplates();
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)));
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)));
// @voba - returns PageData object to be in sync with other fetchers
return new PageData<>(result, 1, result.size(), false);
} }
private AdminSettings loadMailTemplates() throws Exception {
// Map<String, Object> mailTemplates = new HashMap<>();
// private void syncAdminSettings(TenantId tenantId, Edge edge) { Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
// log.trace("[{}] syncAdminSettings [{}]", tenantId, edge.getName()); Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
// try { File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();
// AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"); for (File file : files) {
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)); Map<String, String> mailTemplate = new HashMap<>();
// AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue()); String name = validateName(file.getName());
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)); String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
// AdminSettings systemMailTemplates = loadMailTemplates(); Matcher start = startPattern.matcher(stringTemplate);
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)); Matcher end = endPattern.matcher(stringTemplate);
// AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue()); if (start.find() && end.find()) {
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)); String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
// } catch (Exception e) { String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
// log.error("Can't load admin settings", e); mailTemplate.put("subject", subject);
// } mailTemplate.put("body", body);
// } mailTemplates.put(name, mailTemplate);
// } else {
// private AdminSettings loadMailTemplates() throws Exception { log.error("Can't load mail template from file {}", file.getName());
// Map<String, Object> mailTemplates = new HashMap<>(); }
// Pattern startPattern = Pattern.compile("<div class=\"content\".*?>"); }
// Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>"); AdminSettings adminSettings = new AdminSettings();
// File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles(); adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
// for (File file : files) { adminSettings.setKey("mailTemplates");
// Map<String, String> mailTemplate = new HashMap<>(); adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class));
// String name = validateName(file.getName()); return adminSettings;
// String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8); }
// Matcher start = startPattern.matcher(stringTemplate);
// Matcher end = endPattern.matcher(stringTemplate); private String validateName(String name) throws Exception {
// if (start.find() && end.find()) { StringBuilder nameBuilder = new StringBuilder();
// String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", ""); name = name.replace(".vm", "");
// String subject = StringUtils.substringBetween(body, "<h2>", "</h2>"); String[] nameParts = name.split("\\.");
// mailTemplate.put("subject", subject); if (nameParts.length >= 1) {
// mailTemplate.put("body", body); nameBuilder.append(nameParts[0]);
// mailTemplates.put(name, mailTemplate); for (int i = 1; i < nameParts.length; i++) {
// } else { String word = WordUtils.capitalize(nameParts[i]);
// log.error("Can't load mail template from file {}", file.getName()); nameBuilder.append(word);
// } }
// } return nameBuilder.toString();
// AdminSettings adminSettings = new AdminSettings(); } else {
// adminSettings.setId(new AdminSettingsId(Uuids.timeBased())); throw new Exception("Error during filename validation");
// adminSettings.setKey("mailTemplates"); }
// adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class)); }
// return adminSettings;
// } private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
// AdminSettings tenantMailSettings = new AdminSettings();
// private String validateName(String name) throws Exception { jsonValue.put("useSystemMailSettings", true);
// StringBuilder nameBuilder = new StringBuilder(); tenantMailSettings.setJsonValue(jsonValue);
// name = name.replace(".vm", ""); tenantMailSettings.setKey(key);
// String[] nameParts = name.split("\\."); return tenantMailSettings;
// if (nameParts.length >= 1) { }
// nameBuilder.append(nameParts[0]);
// for (int i = 1; i < nameParts.length; i++) {
// String word = WordUtils.capitalize(nameParts[i]);
// nameBuilder.append(word);
// }
// return nameBuilder.toString();
// } else {
// throw new Exception("Error during filename validation");
// }
// }
//
// private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
// AdminSettings tenantMailSettings = new AdminSettings();
// jsonValue.put("useSystemMailSettings", true);
// tenantMailSettings.setJsonValue(jsonValue);
// tenantMailSettings.setKey(key);
// return tenantMailSettings;
// }
} }

View File

@ -15,10 +15,13 @@
*/ */
package org.thingsboard.server.service.edge.rpc.fetch; package org.thingsboard.server.service.edge.rpc.fetch;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
public abstract class BasePageableEdgeEventFetcher implements EdgeEventFetcher { public abstract class BasePageableEdgeEventFetcher implements EdgeEventFetcher {
protected static final ObjectMapper mapper = new ObjectMapper();
@Override @Override
public PageLink getPageLink(int pageSize) { public PageLink getPageLink(int pageSize) {
return new PageLink(pageSize); return new PageLink(pageSize);

View File

@ -25,5 +25,5 @@ public interface EdgeEventFetcher {
PageLink getPageLink(int pageSize); PageLink getPageLink(int pageSize);
PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink); PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) throws Exception;
} }

View File

@ -72,8 +72,6 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
private static final ReentrantLock deviceCreationLock = new ReentrantLock(); private static final ReentrantLock deviceCreationLock = new ReentrantLock();
// TODO onDeviceUpdateFromEdge onDeviceUpdateToEdge
public ListenableFuture<Void> processDeviceFromEdge(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) { public ListenableFuture<Void> processDeviceFromEdge(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName()); log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
switch (deviceUpdateMsg.getMsgType()) { switch (deviceUpdateMsg.getMsgType()) {

View File

@ -82,7 +82,7 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
List<ListenableFuture<Void>> result = new ArrayList<>(); List<ListenableFuture<Void>> result = new ArrayList<>();
EntityId entityId = constructEntityId(entityData); EntityId entityId = constructEntityId(entityData);
if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg() || entityData.hasAttributesUpdatedMsg()) && entityId != null) { if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg() || entityData.hasAttributesUpdatedMsg()) && entityId != null) {
// TODO: voba - in terms of performance we should not fetch device from DB by id // @voba - in terms of performance we should not fetch device from DB by id
// TbMsgMetaData metaData = constructBaseMsgMetadata(tenantId, entityId); // TbMsgMetaData metaData = constructBaseMsgMetadata(tenantId, entityId);
TbMsgMetaData metaData = new TbMsgMetaData(); TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE); metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);

View File

@ -171,8 +171,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
installation(); installation();
edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
// TODO: voba - should be less, but events from SyncEdgeService stack with events from controller. will be fixed in next releases
// so ideally sync process should check current edge queue and add only missing entities to the edge queue
edgeImitator.expectMessageAmount(9); edgeImitator.expectMessageAmount(9);
edgeImitator.connect(); edgeImitator.connect();
} }

View File

@ -497,7 +497,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
@Override @Override
public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) { public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
// TODO: voba - rewrite 'find' to use native SQL queries instead of fetching relations // TODO: @voba - rewrite 'find' to use native SQL queries instead of fetching relations
log.trace("[{}] Executing findRelatedEdgeIdsByEntityId [{}]", tenantId, entityId); log.trace("[{}] Executing findRelatedEdgeIdsByEntityId [{}]", tenantId, entityId);
if (EntityType.TENANT.equals(entityId.getEntityType()) || if (EntityType.TENANT.equals(entityId.getEntityType()) ||

View File

@ -77,7 +77,7 @@ public abstract class AbstractEntityService {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get(); List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get();
if (entityViews != null && !entityViews.isEmpty()) { if (entityViews != null && !entityViews.isEmpty()) {
EntityView entityView = entityViews.get(0); EntityView entityView = entityViews.get(0);
// TODO: voba - refactor this blocking operation in 3.3+ // TODO: @voba - refactor this blocking operation in 3.3+
Boolean relationExists = relationService.checkRelation(tenantId,edgeId, entityView.getId(), Boolean relationExists = relationService.checkRelation(tenantId,edgeId, entityView.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get(); EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get();
if (relationExists) { if (relationExists) {

View File

@ -223,7 +223,7 @@ public class TbMsgPushToEdgeNode implements TbNode {
private String getScope(Map<String, String> metadata) { private String getScope(Map<String, String> metadata) {
String scope = metadata.get(SCOPE); String scope = metadata.get(SCOPE);
if (StringUtils.isEmpty(scope)) { if (StringUtils.isEmpty(scope)) {
// TODO: voba - move this to configuration of the node UI or some other place // TODO: @voba - move this to configuration of the node UI or some other place
scope = DataConstants.SERVER_SCOPE; scope = DataConstants.SERVER_SCOPE;
} }
return scope; return scope;

View File

@ -188,7 +188,7 @@ export class RuleChainAutocompleteComponent implements ControlValueAccessor, OnI
fetchRuleChain(searchText?: string): Observable<Array<BaseData<EntityId>>> { fetchRuleChain(searchText?: string): Observable<Array<BaseData<EntityId>>> {
this.searchText = searchText; this.searchText = searchText;
// voba: at the moment device profiles are not supported by edge, so 'core' hardcoded // @voba: at the moment device profiles are not supported by edge, so 'core' hardcoded
return this.entityService.getEntitiesByNameFilter(EntityType.RULE_CHAIN, searchText, return this.entityService.getEntitiesByNameFilter(EntityType.RULE_CHAIN, searchText,
50, RuleChainType.CORE, {ignoreLoading: true}); 50, RuleChainType.CORE, {ignoreLoading: true});
} }