Commit 2c826c12cd86a4c27fd3ed74b9640074400adaa1

Authored by Volodymyr Babak
1 parent c43bc3c8

added admin setting fetcher

... ... @@ -635,7 +635,7 @@ public class RuleChainController extends BaseController {
635 635 }
636 636 }
637 637
638   - // TODO: refactor this - add new config to edge rule chain to set it as auto-assign
  638 + // TODO: @voba refactor this - add new config to edge rule chain to set it as auto-assign
639 639 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
640 640 @RequestMapping(value = "/ruleChain/autoAssignToEdgeRuleChains", method = RequestMethod.GET)
641 641 @ResponseBody
... ...
... ... @@ -27,6 +27,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
27 27 import org.thingsboard.server.dao.edge.EdgeEventService;
28 28 import org.thingsboard.server.dao.edge.EdgeService;
29 29 import org.thingsboard.server.dao.rule.RuleChainService;
  30 +import org.thingsboard.server.dao.settings.AdminSettingsService;
30 31 import org.thingsboard.server.dao.user.UserService;
31 32 import org.thingsboard.server.dao.widget.WidgetsBundleService;
32 33 import org.thingsboard.server.queue.util.TbCoreComponent;
... ... @@ -64,6 +65,10 @@ public class EdgeContextComponent {
64 65
65 66 @Lazy
66 67 @Autowired
  68 + private AdminSettingsService adminSettingsService;
  69 +
  70 + @Lazy
  71 + @Autowired
67 72 private AssetService assetService;
68 73
69 74 @Lazy
... ...
... ... @@ -68,6 +68,7 @@ import org.thingsboard.server.gen.edge.UplinkResponseMsg;
68 68 import org.thingsboard.server.gen.edge.UserCredentialsRequestMsg;
69 69 import org.thingsboard.server.gen.edge.WidgetBundleTypesRequestMsg;
70 70 import org.thingsboard.server.service.edge.EdgeContextComponent;
  71 +import org.thingsboard.server.service.edge.rpc.fetch.AdminSettingsEdgeEventFetcher;
71 72 import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher;
72 73 import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher;
73 74 import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher;
... ... @@ -207,8 +208,7 @@ public final class EdgeGrpcSession implements Closeable {
207 208 startProcessingEdgeEvents(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId()));
208 209 }
209 210
210   - // TODO: voba - implement this functionality
211   - // syncAdminSettings(edge);
  211 + startProcessingEdgeEvents(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService()));
212 212
213 213 startProcessingEdgeEvents(new AssetsEdgeEventFetcher(ctx.getAssetService()));
214 214 startProcessingEdgeEvents(new DashboardsEdgeEventFetcher(ctx.getDashboardService()));
... ... @@ -285,7 +285,7 @@ public final class EdgeGrpcSession implements Closeable {
285 285 sendDownlinkMsg(edgeConfigMsg);
286 286 }
287 287
288   - void processEdgeEvents() throws ExecutionException, InterruptedException {
  288 + void processEdgeEvents() throws Exception {
289 289 log.trace("[{}] processHandleMessages started", this.sessionId);
290 290 if (isConnected() && isSyncCompleted()) {
291 291 Long queueStartTs = getQueueStartTs().get();
... ... @@ -301,7 +301,7 @@ public final class EdgeGrpcSession implements Closeable {
301 301 log.trace("[{}] processHandleMessages finished", this.sessionId);
302 302 }
303 303
304   - private UUID startProcessingEdgeEvents(EdgeEventFetcher fetcher) throws InterruptedException {
  304 + private UUID startProcessingEdgeEvents(EdgeEventFetcher fetcher) throws Exception {
305 305 PageLink pageLink = fetcher.getPageLink(ctx.getEdgeEventStorageSettings().getMaxReadRecordsCount());
306 306 PageData<EdgeEvent> pageData;
307 307 UUID ifOffset = null;
... ...
... ... @@ -41,7 +41,7 @@ public class DeviceProfileMsgConstructor {
41 41 .setDefault(deviceProfile.isDefault())
42 42 .setType(deviceProfile.getType().name())
43 43 .setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile.getProfileData())));
44   - // TODO: voba - should this be always null at the moment??
  44 + // TODO: @voba - add possibility to setup edge rule chain as device profile default
45 45 // if (deviceProfile.getDefaultRuleChainId() != null) {
46 46 // builder.setDefaultRuleChainIdMSB(deviceProfile.getDefaultRuleChainId().getId().getMostSignificantBits())
47 47 // .setDefaultRuleChainIdLSB(deviceProfile.getDefaultRuleChainId().getId().getLeastSignificantBits());
... ...
... ... @@ -15,90 +15,115 @@
15 15 */
16 16 package org.thingsboard.server.service.edge.rpc.fetch;
17 17
  18 +import com.datastax.oss.driver.api.core.uuid.Uuids;
  19 +import com.fasterxml.jackson.databind.JsonNode;
  20 +import com.fasterxml.jackson.databind.node.ObjectNode;
18 21 import lombok.AllArgsConstructor;
19 22 import lombok.extern.slf4j.Slf4j;
  23 +import org.apache.commons.io.FileUtils;
  24 +import org.apache.commons.lang3.StringUtils;
  25 +import org.apache.commons.lang3.text.WordUtils;
  26 +import org.springframework.core.io.DefaultResourceLoader;
  27 +import org.thingsboard.server.common.data.AdminSettings;
20 28 import org.thingsboard.server.common.data.edge.EdgeEvent;
  29 +import org.thingsboard.server.common.data.edge.EdgeEventActionType;
  30 +import org.thingsboard.server.common.data.edge.EdgeEventType;
  31 +import org.thingsboard.server.common.data.id.AdminSettingsId;
21 32 import org.thingsboard.server.common.data.id.EdgeId;
22 33 import org.thingsboard.server.common.data.id.TenantId;
23 34 import org.thingsboard.server.common.data.page.PageData;
24 35 import org.thingsboard.server.common.data.page.PageLink;
  36 +import org.thingsboard.server.dao.settings.AdminSettingsService;
  37 +import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
  38 +
  39 +import java.io.File;
  40 +import java.nio.charset.StandardCharsets;
  41 +import java.util.ArrayList;
  42 +import java.util.HashMap;
  43 +import java.util.List;
  44 +import java.util.Map;
  45 +import java.util.regex.Matcher;
  46 +import java.util.regex.Pattern;
25 47
26 48 @AllArgsConstructor
27 49 @Slf4j
28 50 public class AdminSettingsEdgeEventFetcher extends BasePageableEdgeEventFetcher {
29 51
  52 + private final AdminSettingsService adminSettingsService;
  53 +
30 54 @Override
31   - public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) {
32   - return null;
  55 + public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) throws Exception {
  56 + List<EdgeEvent> result = new ArrayList<>();
  57 +
  58 + AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
  59 + result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
  60 + EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)));
  61 +
  62 + AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
  63 + result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
  64 + EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)));
  65 +
  66 + AdminSettings systemMailTemplates = loadMailTemplates();
  67 + result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
  68 + EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)));
  69 +
  70 + AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
  71 + result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
  72 + EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)));
  73 +
  74 + // @voba - returns PageData object to be in sync with other fetchers
  75 + return new PageData<>(result, 1, result.size(), false);
33 76 }
34 77
  78 + private AdminSettings loadMailTemplates() throws Exception {
  79 + Map<String, Object> mailTemplates = new HashMap<>();
  80 + Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
  81 + Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
  82 + File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();
  83 + for (File file : files) {
  84 + Map<String, String> mailTemplate = new HashMap<>();
  85 + String name = validateName(file.getName());
  86 + String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
  87 + Matcher start = startPattern.matcher(stringTemplate);
  88 + Matcher end = endPattern.matcher(stringTemplate);
  89 + if (start.find() && end.find()) {
  90 + String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
  91 + String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
  92 + mailTemplate.put("subject", subject);
  93 + mailTemplate.put("body", body);
  94 + mailTemplates.put(name, mailTemplate);
  95 + } else {
  96 + log.error("Can't load mail template from file {}", file.getName());
  97 + }
  98 + }
  99 + AdminSettings adminSettings = new AdminSettings();
  100 + adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
  101 + adminSettings.setKey("mailTemplates");
  102 + adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class));
  103 + return adminSettings;
  104 + }
35 105
36   -//
37   -// private void syncAdminSettings(TenantId tenantId, Edge edge) {
38   -// log.trace("[{}] syncAdminSettings [{}]", tenantId, edge.getName());
39   -// try {
40   -// AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
41   -// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings));
42   -// AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
43   -// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings));
44   -// AdminSettings systemMailTemplates = loadMailTemplates();
45   -// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates));
46   -// AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
47   -// saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates));
48   -// } catch (Exception e) {
49   -// log.error("Can't load admin settings", e);
50   -// }
51   -// }
52   -//
53   -// private AdminSettings loadMailTemplates() throws Exception {
54   -// Map<String, Object> mailTemplates = new HashMap<>();
55   -// Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
56   -// Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
57   -// File[] files = new DefaultResourceLoader().getResource("classpath:/templates/").getFile().listFiles();
58   -// for (File file : files) {
59   -// Map<String, String> mailTemplate = new HashMap<>();
60   -// String name = validateName(file.getName());
61   -// String stringTemplate = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
62   -// Matcher start = startPattern.matcher(stringTemplate);
63   -// Matcher end = endPattern.matcher(stringTemplate);
64   -// if (start.find() && end.find()) {
65   -// String body = StringUtils.substringBetween(stringTemplate, start.group(), end.group()).replaceAll("\t", "");
66   -// String subject = StringUtils.substringBetween(body, "<h2>", "</h2>");
67   -// mailTemplate.put("subject", subject);
68   -// mailTemplate.put("body", body);
69   -// mailTemplates.put(name, mailTemplate);
70   -// } else {
71   -// log.error("Can't load mail template from file {}", file.getName());
72   -// }
73   -// }
74   -// AdminSettings adminSettings = new AdminSettings();
75   -// adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
76   -// adminSettings.setKey("mailTemplates");
77   -// adminSettings.setJsonValue(mapper.convertValue(mailTemplates, JsonNode.class));
78   -// return adminSettings;
79   -// }
80   -//
81   -// private String validateName(String name) throws Exception {
82   -// StringBuilder nameBuilder = new StringBuilder();
83   -// name = name.replace(".vm", "");
84   -// String[] nameParts = name.split("\\.");
85   -// if (nameParts.length >= 1) {
86   -// nameBuilder.append(nameParts[0]);
87   -// for (int i = 1; i < nameParts.length; i++) {
88   -// String word = WordUtils.capitalize(nameParts[i]);
89   -// nameBuilder.append(word);
90   -// }
91   -// return nameBuilder.toString();
92   -// } else {
93   -// throw new Exception("Error during filename validation");
94   -// }
95   -// }
96   -//
97   -// private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
98   -// AdminSettings tenantMailSettings = new AdminSettings();
99   -// jsonValue.put("useSystemMailSettings", true);
100   -// tenantMailSettings.setJsonValue(jsonValue);
101   -// tenantMailSettings.setKey(key);
102   -// return tenantMailSettings;
103   -// }
  106 + private String validateName(String name) throws Exception {
  107 + StringBuilder nameBuilder = new StringBuilder();
  108 + name = name.replace(".vm", "");
  109 + String[] nameParts = name.split("\\.");
  110 + if (nameParts.length >= 1) {
  111 + nameBuilder.append(nameParts[0]);
  112 + for (int i = 1; i < nameParts.length; i++) {
  113 + String word = WordUtils.capitalize(nameParts[i]);
  114 + nameBuilder.append(word);
  115 + }
  116 + return nameBuilder.toString();
  117 + } else {
  118 + throw new Exception("Error during filename validation");
  119 + }
  120 + }
  121 +
  122 + private AdminSettings convertToTenantAdminSettings(String key, ObjectNode jsonValue) {
  123 + AdminSettings tenantMailSettings = new AdminSettings();
  124 + jsonValue.put("useSystemMailSettings", true);
  125 + tenantMailSettings.setJsonValue(jsonValue);
  126 + tenantMailSettings.setKey(key);
  127 + return tenantMailSettings;
  128 + }
104 129 }
... ...
... ... @@ -15,10 +15,13 @@
15 15 */
16 16 package org.thingsboard.server.service.edge.rpc.fetch;
17 17
  18 +import com.fasterxml.jackson.databind.ObjectMapper;
18 19 import org.thingsboard.server.common.data.page.PageLink;
19 20
20 21 public abstract class BasePageableEdgeEventFetcher implements EdgeEventFetcher {
21 22
  23 + protected static final ObjectMapper mapper = new ObjectMapper();
  24 +
22 25 @Override
23 26 public PageLink getPageLink(int pageSize) {
24 27 return new PageLink(pageSize);
... ...
... ... @@ -25,5 +25,5 @@ public interface EdgeEventFetcher {
25 25
26 26 PageLink getPageLink(int pageSize);
27 27
28   - PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink);
  28 + PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, EdgeId edgeId, PageLink pageLink) throws Exception;
29 29 }
... ...
... ... @@ -72,8 +72,6 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
72 72
73 73 private static final ReentrantLock deviceCreationLock = new ReentrantLock();
74 74
75   - // TODO onDeviceUpdateFromEdge onDeviceUpdateToEdge
76   -
77 75 public ListenableFuture<Void> processDeviceFromEdge(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
78 76 log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName());
79 77 switch (deviceUpdateMsg.getMsgType()) {
... ...
... ... @@ -82,7 +82,7 @@ public class TelemetryEdgeProcessor extends BaseEdgeProcessor {
82 82 List<ListenableFuture<Void>> result = new ArrayList<>();
83 83 EntityId entityId = constructEntityId(entityData);
84 84 if ((entityData.hasPostAttributesMsg() || entityData.hasPostTelemetryMsg() || entityData.hasAttributesUpdatedMsg()) && entityId != null) {
85   - // TODO: voba - in terms of performance we should not fetch device from DB by id
  85 + // @voba - in terms of performance we should not fetch device from DB by id
86 86 // TbMsgMetaData metaData = constructBaseMsgMetadata(tenantId, entityId);
87 87 TbMsgMetaData metaData = new TbMsgMetaData();
88 88 metaData.putValue(DataConstants.MSG_SOURCE_KEY, DataConstants.EDGE_MSG_SOURCE);
... ...
... ... @@ -171,8 +171,6 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
171 171 installation();
172 172
173 173 edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
174   - // TODO: voba - should be less, but events from SyncEdgeService stack with events from controller. will be fixed in next releases
175   - // so ideally sync process should check current edge queue and add only missing entities to the edge queue
176 174 edgeImitator.expectMessageAmount(9);
177 175 edgeImitator.connect();
178 176 }
... ...
... ... @@ -497,7 +497,7 @@ public class EdgeServiceImpl extends AbstractEntityService implements EdgeServic
497 497
498 498 @Override
499 499 public ListenableFuture<List<EdgeId>> findRelatedEdgeIdsByEntityId(TenantId tenantId, EntityId entityId) {
500   - // TODO: voba - rewrite 'find' to use native SQL queries instead of fetching relations
  500 + // TODO: @voba - rewrite 'find' to use native SQL queries instead of fetching relations
501 501
502 502 log.trace("[{}] Executing findRelatedEdgeIdsByEntityId [{}]", tenantId, entityId);
503 503 if (EntityType.TENANT.equals(entityId.getEntityType()) ||
... ...
... ... @@ -77,7 +77,7 @@ public abstract class AbstractEntityService {
77 77 List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId).get();
78 78 if (entityViews != null && !entityViews.isEmpty()) {
79 79 EntityView entityView = entityViews.get(0);
80   - // TODO: voba - refactor this blocking operation in 3.3+
  80 + // TODO: @voba - refactor this blocking operation in 3.3+
81 81 Boolean relationExists = relationService.checkRelation(tenantId,edgeId, entityView.getId(),
82 82 EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE).get();
83 83 if (relationExists) {
... ...
... ... @@ -223,7 +223,7 @@ public class TbMsgPushToEdgeNode implements TbNode {
223 223 private String getScope(Map<String, String> metadata) {
224 224 String scope = metadata.get(SCOPE);
225 225 if (StringUtils.isEmpty(scope)) {
226   - // TODO: voba - move this to configuration of the node UI or some other place
  226 + // TODO: @voba - move this to configuration of the node UI or some other place
227 227 scope = DataConstants.SERVER_SCOPE;
228 228 }
229 229 return scope;
... ...
... ... @@ -188,7 +188,7 @@ export class RuleChainAutocompleteComponent implements ControlValueAccessor, OnI
188 188
189 189 fetchRuleChain(searchText?: string): Observable<Array<BaseData<EntityId>>> {
190 190 this.searchText = searchText;
191   - // voba: at the moment device profiles are not supported by edge, so 'core' hardcoded
  191 + // @voba: at the moment device profiles are not supported by edge, so 'core' hardcoded
192 192 return this.entityService.getEntitiesByNameFilter(EntityType.RULE_CHAIN, searchText,
193 193 50, RuleChainType.CORE, {ignoreLoading: true});
194 194 }
... ...