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')")
@RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET)
@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.EdgeService;
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.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -62,6 +63,10 @@ public class EdgeContextComponent {
@Autowired
private EdgeEventService edgeEventService;
@Lazy
@Autowired
private AdminSettingsService adminSettingsService;
@Lazy
@Autowired
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.WidgetBundleTypesRequestMsg;
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.CustomerUsersEdgeEventFetcher;
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()));
}
// TODO: voba - implement this functionality
// syncAdminSettings(edge);
startProcessingEdgeEvents(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService()));
startProcessingEdgeEvents(new AssetsEdgeEventFetcher(ctx.getAssetService()));
startProcessingEdgeEvents(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
@ -285,7 +285,7 @@ public final class EdgeGrpcSession implements Closeable {
sendDownlinkMsg(edgeConfigMsg);
}
void processEdgeEvents() throws ExecutionException, InterruptedException {
void processEdgeEvents() throws Exception {
log.trace("[{}] processHandleMessages started", this.sessionId);
if (isConnected() && isSyncCompleted()) {
Long queueStartTs = getQueueStartTs().get();
@ -301,7 +301,7 @@ public final class EdgeGrpcSession implements Closeable {
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());
PageData<EdgeEvent> pageData;
UUID ifOffset = null;

View File

@ -41,7 +41,7 @@ public class DeviceProfileMsgConstructor {
.setDefault(deviceProfile.isDefault())
.setType(deviceProfile.getType().name())
.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) {
// builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
// .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());

View File

@ -15,90 +15,115 @@
*/
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.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.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.TenantId;
import org.thingsboard.server.common.data.page.PageData;
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
@Slf4j
public class AdminSettingsEdgeEventFetcher extends BasePageableEdgeEventFetcher {
private final AdminSettingsService adminSettingsService;
@Override
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) {
return null;
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) throws Exception {
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<>();
Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();
for (File file : files) {
Map<String, String> mailTemplate = new HashMap<>();
String name = validateName(file.getName());
String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
Matcher start = startPattern.matcher(stringTemplate);
Matcher end = endPattern.matcher(stringTemplate);
if (start.find() && end.find()) {
String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
mailTemplate.put("subject", subject);
mailTemplate.put("body", body);
mailTemplates.put(name, mailTemplate);
} else {
log.error("Can't load mail template from file {}", file.getName());
}
}
AdminSettings adminSettings = new AdminSettings();
adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
adminSettings.setKey("mailTemplates");
adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class));
return adminSettings;
}
//
// private void syncAdminSettings(TenantId tenantId, Edge edge) {
// log.trace("[{}] syncAdminSettings [{}]", tenantId, edge.getName());
// try {
// AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings));
// AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings));
// AdminSettings systemMailTemplates = loadMailTemplates();
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates));
// AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates));
// } catch (Exception e) {
// log.error("Can't load admin settings", e);
// }
// }
//
// private AdminSettings loadMailTemplates() throws Exception {
// Map<String, Object> mailTemplates = new HashMap<>();
// Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
// Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
// File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();
// for (File file : files) {
// Map<String, String> mailTemplate = new HashMap<>();
// String name = validateName(file.getName());
// String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
// Matcher start = startPattern.matcher(stringTemplate);
// Matcher end = endPattern.matcher(stringTemplate);
// if (start.find() && end.find()) {
// String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
// String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
// mailTemplate.put("subject", subject);
// mailTemplate.put("body", body);
// mailTemplates.put(name, mailTemplate);
// } else {
// log.error("Can't load mail template from file {}", file.getName());
// }
// }
// AdminSettings adminSettings = new AdminSettings();
// adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
// adminSettings.setKey("mailTemplates");
// adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class));
// return adminSettings;
// }
//
// private String validateName(String name) throws Exception {
// StringBuilder nameBuilder = new StringBuilder();
// name = name.replace(".vm", "");
// String[] nameParts = name.split("\\.");
// 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;
// }
private String validateName(String name) throws Exception {
StringBuilder nameBuilder = new StringBuilder();
name = name.replace(".vm", "");
String[] nameParts = name.split("\\.");
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;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.thingsboard.server.common.data.page.PageLink;
public abstract class BasePageableEdgeEventFetcher implements EdgeEventFetcher {
protected static final ObjectMapper mapper = new ObjectMapper();
@Override
public PageLink getPageLink(int pageSize) {
return new PageLink(pageSize);

View File

@ -25,5 +25,5 @@ public interface EdgeEventFetcher {
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();
// TODO onDeviceUpdateFromEdge onDeviceUpdateToEdge
public ListenableFuture<Void> processDeviceFromEdge(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
switch (deviceUpdateMsg.getMsgType()) {

View File

@ -82,7 +82,7 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
List<ListenableFuture<Void>> result = new ArrayList<>();
EntityId entityId = constructEntityId(entityData);
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 = new TbMsgMetaData();
metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);

View File

@ -171,8 +171,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
installation();
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.connect();
}

View File

@ -497,7 +497,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
@Override
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);
if (EntityType.TENANT.equals(entityId.getEntityType()) ||

View File

@ -77,7 +77,7 @@ public abstract class AbstractEntityService {
List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get();
if (entityViews != null && !entityViews.isEmpty()) {
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(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get();
if (relationExists) {

View File

@ -223,7 +223,7 @@ public class TbMsgPushToEdgeNode implements TbNode {
private String getScope(Map<String, String> metadata) {
String scope = metadata.get(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;
}
return scope;

View File

@ -188,7 +188,7 @@ export class RuleChainAutocompleteComponent implements ControlValueAccessor, OnI
fetchRuleChain(searchText?: string): Observable<Array<BaseData<EntityId>>> {
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,
50, RuleChainType.CORE, {ignoreLoading: true});
}