Merge pull request #9598 from volodymyr-babak/edge-admin-set-fix
Admin Edge Fetcher updates. Resource Edge Processor updates.
This commit is contained in:
		
						commit
						d82646a691
					
				@ -15,7 +15,6 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.service.edge;
 | 
			
		||||
 | 
			
		||||
import freemarker.template.Configuration;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Lazy;
 | 
			
		||||
@ -87,9 +86,6 @@ public class EdgeContextComponent {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private AdminSettingsService adminSettingsService;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private Configuration freemarkerConfig;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DeviceService deviceService;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ public class EdgeSyncCursor {
 | 
			
		||||
            fetchers.add(new TenantEdgeEventFetcher(ctx.getTenantService()));
 | 
			
		||||
            fetchers.add(new QueuesEdgeEventFetcher(ctx.getQueueService()));
 | 
			
		||||
            fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService()));
 | 
			
		||||
            fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), ctx.getFreemarkerConfig()));
 | 
			
		||||
            fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService()));
 | 
			
		||||
            fetchers.add(new TenantAdminUsersEdgeEventFetcher(ctx.getUserService()));
 | 
			
		||||
            Customer publicCustomer = ctx.getCustomerService().findOrCreatePublicCustomer(edge.getTenantId());
 | 
			
		||||
            fetchers.add(new CustomerEdgeEventFetcher(publicCustomer.getId()));
 | 
			
		||||
 | 
			
		||||
@ -15,146 +15,51 @@
 | 
			
		||||
 */
 | 
			
		||||
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 freemarker.template.Configuration;
 | 
			
		||||
import freemarker.template.Template;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.apache.commons.lang3.text.WordUtils;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.server.common.data.AdminSettings;
 | 
			
		||||
import org.thingsboard.server.common.data.EdgeUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.StringUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.edge.Edge;
 | 
			
		||||
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 java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
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 implements EdgeEventFetcher {
 | 
			
		||||
 | 
			
		||||
    private final AdminSettingsService adminSettingsService;
 | 
			
		||||
    private final Configuration freemarkerConfig;
 | 
			
		||||
 | 
			
		||||
    private static final Pattern startPattern = Pattern.compile("<div class=\"content\".*?>");
 | 
			
		||||
    private static final Pattern endPattern = Pattern.compile("<div class=\"footer\".*?>");
 | 
			
		||||
 | 
			
		||||
    private static final List<String> templatesNames = Arrays.asList(
 | 
			
		||||
            "account.activated.ftl",
 | 
			
		||||
            "account.lockout.ftl",
 | 
			
		||||
            "activation.ftl",
 | 
			
		||||
            "password.was.reset.ftl",
 | 
			
		||||
            "reset.password.ftl",
 | 
			
		||||
            "test.ftl");
 | 
			
		||||
 | 
			
		||||
    // TODO: @voba fix format of next templates
 | 
			
		||||
    // "state.disabled.ftl",
 | 
			
		||||
    // "state.enabled.ftl",
 | 
			
		||||
    // "state.warning.ftl",
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageLink getPageLink(int pageSize) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) throws Exception {
 | 
			
		||||
        List<EdgeEvent> result = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
 | 
			
		||||
        result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
 | 
			
		||||
                EdgeEventActionType.UPDATED, null, JacksonUtil.valueToTree(systemMailSettings)));
 | 
			
		||||
 | 
			
		||||
        AdminSettings tenantMailSettings = convertToTenantAdminSettings(tenantId, systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
 | 
			
		||||
        result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
 | 
			
		||||
                EdgeEventActionType.UPDATED, null, JacksonUtil.valueToTree(tenantMailSettings)));
 | 
			
		||||
 | 
			
		||||
        AdminSettings systemMailTemplates = loadMailTemplates(tenantId);
 | 
			
		||||
        result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
 | 
			
		||||
                EdgeEventActionType.UPDATED, null, JacksonUtil.valueToTree(systemMailTemplates)));
 | 
			
		||||
 | 
			
		||||
        AdminSettings tenantMailTemplates = convertToTenantAdminSettings(tenantId, systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
 | 
			
		||||
        result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
 | 
			
		||||
                EdgeEventActionType.UPDATED, null, JacksonUtil.valueToTree(tenantMailTemplates)));
 | 
			
		||||
    public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) {
 | 
			
		||||
        List<EdgeEvent> result = fetchAdminSettingsForKeys(tenantId, edge.getId(), List.of("general", "mail", "connectivity", "jwt"));
 | 
			
		||||
 | 
			
		||||
        // return PageData object to be in sync with other fetchers
 | 
			
		||||
        return new PageData<>(result, 1, result.size(), false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private AdminSettings loadMailTemplates(TenantId tenantId) throws Exception {
 | 
			
		||||
        Map<String, Object> mailTemplates = new HashMap<>();
 | 
			
		||||
        for (String templatesName : templatesNames) {
 | 
			
		||||
            Template template = freemarkerConfig.getTemplate(templatesName);
 | 
			
		||||
            if (template != null) {
 | 
			
		||||
                String name = validateName(template.getName());
 | 
			
		||||
                Map<String, String> mailTemplate = getMailTemplateFromFile(template.toString());
 | 
			
		||||
                if (mailTemplate != null) {
 | 
			
		||||
                    mailTemplates.put(name, mailTemplate);
 | 
			
		||||
                } else {
 | 
			
		||||
                    log.error("[{}] Can't load mail template from file {}", tenantId, template.getName());
 | 
			
		||||
                }
 | 
			
		||||
    private List<EdgeEvent> fetchAdminSettingsForKeys(TenantId tenantId, EdgeId edgeId, List<String> keys) {
 | 
			
		||||
        List<EdgeEvent> result = new ArrayList<>();
 | 
			
		||||
        for (String key : keys) {
 | 
			
		||||
            AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key);
 | 
			
		||||
            if (adminSettings != null) {
 | 
			
		||||
                result.add(EdgeUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS,
 | 
			
		||||
                        EdgeEventActionType.UPDATED, null, JacksonUtil.valueToTree(adminSettings)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        AdminSettings adminSettings = new AdminSettings();
 | 
			
		||||
        adminSettings.setId(new AdminSettingsId(Uuids.timeBased()));
 | 
			
		||||
        adminSettings.setKey("mailTemplates");
 | 
			
		||||
        adminSettings.setJsonValue(JacksonUtil.convertValue(mailTemplates, JsonNode.class));
 | 
			
		||||
        return adminSettings;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Map<String, String> getMailTemplateFromFile(String stringTemplate) {
 | 
			
		||||
        Map<String, String> mailTemplate = new HashMap<>();
 | 
			
		||||
        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);
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return mailTemplate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String validateName(String name) throws Exception {
 | 
			
		||||
        StringBuilder nameBuilder = new StringBuilder();
 | 
			
		||||
        name = name.replace(".ftl", "");
 | 
			
		||||
        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(TenantId tenantId, String key, ObjectNode jsonValue) {
 | 
			
		||||
        AdminSettings tenantMailSettings = new AdminSettings();
 | 
			
		||||
        tenantMailSettings.setTenantId(tenantId);
 | 
			
		||||
        jsonValue.put("useSystemMailSettings", true);
 | 
			
		||||
        tenantMailSettings.setJsonValue(jsonValue);
 | 
			
		||||
        tenantMailSettings.setKey(key);
 | 
			
		||||
        return tenantMailSettings;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -467,9 +467,9 @@ public abstract class BaseEdgeProcessor {
 | 
			
		||||
        EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
 | 
			
		||||
        EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
 | 
			
		||||
        EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
 | 
			
		||||
        EdgeId sourceEdgeId = safeGetEdgeId(edgeNotificationMsg.getSourceEdgeIdMSB(), edgeNotificationMsg.getSourceEdgeIdLSB());
 | 
			
		||||
        EdgeId originatorEdgeId = safeGetEdgeId(edgeNotificationMsg.getOriginatorEdgeIdMSB(), edgeNotificationMsg.getOriginatorEdgeIdLSB());
 | 
			
		||||
        if (type.isAllEdgesRelated()) {
 | 
			
		||||
            return processEntityNotificationForAllEdges(tenantId, type, actionType, entityId, sourceEdgeId);
 | 
			
		||||
            return processEntityNotificationForAllEdges(tenantId, type, actionType, entityId, originatorEdgeId);
 | 
			
		||||
        } else {
 | 
			
		||||
            JsonNode body = JacksonUtil.toJsonNode(edgeNotificationMsg.getBody());
 | 
			
		||||
            EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB());
 | 
			
		||||
@ -481,19 +481,19 @@ public abstract class BaseEdgeProcessor {
 | 
			
		||||
                    if (edgeId != null) {
 | 
			
		||||
                        return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, body);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return processNotificationToRelatedEdges(tenantId, entityId, type, actionType, sourceEdgeId);
 | 
			
		||||
                        return processNotificationToRelatedEdges(tenantId, entityId, type, actionType, originatorEdgeId);
 | 
			
		||||
                    }
 | 
			
		||||
                case DELETED:
 | 
			
		||||
                    EdgeEventActionType deleted = EdgeEventActionType.DELETED;
 | 
			
		||||
                    if (edgeId != null) {
 | 
			
		||||
                        return saveEdgeEvent(tenantId, edgeId, type, deleted, entityId, body);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return Futures.transform(Futures.allAsList(processActionForAllEdgesByTenantId(tenantId, type, deleted, entityId, body, sourceEdgeId)),
 | 
			
		||||
                        return Futures.transform(Futures.allAsList(processActionForAllEdgesByTenantId(tenantId, type, deleted, entityId, body, originatorEdgeId)),
 | 
			
		||||
                                voids -> null, dbCallbackExecutorService);
 | 
			
		||||
                    }
 | 
			
		||||
                case ASSIGNED_TO_EDGE:
 | 
			
		||||
                case UNASSIGNED_FROM_EDGE:
 | 
			
		||||
                    if (sourceEdgeId == null) {
 | 
			
		||||
                    if (originatorEdgeId == null) {
 | 
			
		||||
                        ListenableFuture<Void> future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, body);
 | 
			
		||||
                        return Futures.transformAsync(future, unused -> {
 | 
			
		||||
                            if (type.equals(EdgeEventType.RULE_CHAIN)) {
 | 
			
		||||
 | 
			
		||||
@ -71,7 +71,7 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor {
 | 
			
		||||
    public ListenableFuture<Void> processAlarmNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
 | 
			
		||||
        EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
 | 
			
		||||
        AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
 | 
			
		||||
        EdgeId sourceEdgeId = safeGetEdgeId(edgeNotificationMsg.getSourceEdgeIdMSB(), edgeNotificationMsg.getSourceEdgeIdLSB());
 | 
			
		||||
        EdgeId originatorEdgeId = safeGetEdgeId(edgeNotificationMsg.getOriginatorEdgeIdMSB(), edgeNotificationMsg.getOriginatorEdgeIdLSB());
 | 
			
		||||
        switch (actionType) {
 | 
			
		||||
            case DELETED:
 | 
			
		||||
                Alarm deletedAlarm = JacksonUtil.fromString(edgeNotificationMsg.getBody(), Alarm.class);
 | 
			
		||||
@ -79,7 +79,7 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor {
 | 
			
		||||
                    return Futures.immediateFuture(null);
 | 
			
		||||
                }
 | 
			
		||||
                List<ListenableFuture<Void>> delFutures = pushEventToAllRelatedEdges(tenantId, deletedAlarm.getOriginator(),
 | 
			
		||||
                        alarmId, actionType, JacksonUtil.valueToTree(deletedAlarm), sourceEdgeId);
 | 
			
		||||
                        alarmId, actionType, JacksonUtil.valueToTree(deletedAlarm), originatorEdgeId);
 | 
			
		||||
                return Futures.transform(Futures.allAsList(delFutures), voids -> null, dbCallbackExecutorService);
 | 
			
		||||
            default:
 | 
			
		||||
                ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
 | 
			
		||||
@ -92,7 +92,7 @@ public class AlarmEdgeProcessor extends BaseAlarmProcessor {
 | 
			
		||||
                        return Futures.immediateFuture(null);
 | 
			
		||||
                    }
 | 
			
		||||
                    List<ListenableFuture<Void>> futures = pushEventToAllRelatedEdges(tenantId, alarm.getOriginator(),
 | 
			
		||||
                            alarmId, actionType, null, sourceEdgeId);
 | 
			
		||||
                            alarmId, actionType, null, originatorEdgeId);
 | 
			
		||||
                    return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
 | 
			
		||||
                }, dbCallbackExecutorService);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -71,10 +71,12 @@ public class RelationEdgeProcessor extends BaseRelationProcessor {
 | 
			
		||||
        if (relation == null || (relation.getFrom().getEntityType().equals(EntityType.EDGE) || relation.getTo().getEntityType().equals(EntityType.EDGE))) {
 | 
			
		||||
            return Futures.immediateFuture(null);
 | 
			
		||||
        }
 | 
			
		||||
        EdgeId sourceEdgeId = safeGetEdgeId(edgeNotificationMsg.getOriginatorEdgeIdMSB(), edgeNotificationMsg.getOriginatorEdgeIdLSB());
 | 
			
		||||
 | 
			
		||||
        Set<EdgeId> uniqueEdgeIds = new HashSet<>();
 | 
			
		||||
        uniqueEdgeIds.addAll(edgeService.findAllRelatedEdgeIds(tenantId, relation.getTo()));
 | 
			
		||||
        uniqueEdgeIds.addAll(edgeService.findAllRelatedEdgeIds(tenantId, relation.getFrom()));
 | 
			
		||||
        uniqueEdgeIds.remove(sourceEdgeId);
 | 
			
		||||
        if (uniqueEdgeIds.isEmpty()) {
 | 
			
		||||
            return Futures.immediateFuture(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -18,17 +18,20 @@ package org.thingsboard.server.service.edge.rpc.processor.resource;
 | 
			
		||||
import com.datastax.oss.driver.api.core.uuid.Uuids;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.thingsboard.server.common.data.ResourceType;
 | 
			
		||||
import org.thingsboard.server.common.data.StringUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.TbResource;
 | 
			
		||||
import org.thingsboard.server.common.data.TbResourceInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TbResourceId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageDataIterable;
 | 
			
		||||
import org.thingsboard.server.gen.edge.v1.ResourceUpdateMsg;
 | 
			
		||||
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
 | 
			
		||||
 | 
			
		||||
    protected void saveOrUpdateTbResource(TenantId tenantId, TbResourceId tbResourceId, ResourceUpdateMsg resourceUpdateMsg) {
 | 
			
		||||
    protected boolean saveOrUpdateTbResource(TenantId tenantId, TbResourceId tbResourceId, ResourceUpdateMsg resourceUpdateMsg) {
 | 
			
		||||
        boolean resourceKeyUpdated = false;
 | 
			
		||||
        try {
 | 
			
		||||
            boolean created = false;
 | 
			
		||||
            TbResource resource = resourceService.findResourceById(tenantId, tbResourceId);
 | 
			
		||||
@ -42,9 +45,21 @@ public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
 | 
			
		||||
                resource.setCreatedTime(Uuids.unixTimestamp(tbResourceId.getId()));
 | 
			
		||||
                created = true;
 | 
			
		||||
            }
 | 
			
		||||
            String resourceKey = resourceUpdateMsg.getResourceKey();
 | 
			
		||||
            ResourceType resourceType = ResourceType.valueOf(resourceUpdateMsg.getResourceType());
 | 
			
		||||
            PageDataIterable<TbResource> resourcesIterable = new PageDataIterable<>(
 | 
			
		||||
                    link -> resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, resourceType, link), 1024);
 | 
			
		||||
            for (TbResource tbResource : resourcesIterable) {
 | 
			
		||||
                if (tbResource.getResourceKey().equals(resourceUpdateMsg.getResourceKey()) && !tbResourceId.equals(tbResource.getId())) {
 | 
			
		||||
                    resourceKey = StringUtils.randomAlphabetic(15) + "_" + resourceKey;
 | 
			
		||||
                    log.warn("[{}] Resource with resource type {} and key {} already exists. Renaming resource key to {}",
 | 
			
		||||
                            tenantId, resourceType, resourceUpdateMsg.getResourceKey(), resourceKey);
 | 
			
		||||
                    resourceKeyUpdated = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            resource.setTitle(resourceUpdateMsg.getTitle());
 | 
			
		||||
            resource.setResourceKey(resourceUpdateMsg.getResourceKey());
 | 
			
		||||
            resource.setResourceType(ResourceType.valueOf(resourceUpdateMsg.getResourceType()));
 | 
			
		||||
            resource.setResourceKey(resourceKey);
 | 
			
		||||
            resource.setResourceType(resourceType);
 | 
			
		||||
            resource.setFileName(resourceUpdateMsg.getFileName());
 | 
			
		||||
            resource.setData(resourceUpdateMsg.hasData() ? resourceUpdateMsg.getData() : null);
 | 
			
		||||
            resource.setEtag(resourceUpdateMsg.hasEtag() ? resourceUpdateMsg.getEtag() : null);
 | 
			
		||||
@ -57,5 +72,6 @@ public abstract class BaseResourceProcessor extends BaseEdgeProcessor {
 | 
			
		||||
            log.error("[{}] Failed to process resource update msg [{}]", tenantId, resourceUpdateMsg, e);
 | 
			
		||||
            throw e;
 | 
			
		||||
        }
 | 
			
		||||
        return resourceKeyUpdated;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,8 @@ import org.thingsboard.server.common.data.EdgeUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.TbResource;
 | 
			
		||||
import org.thingsboard.server.common.data.edge.Edge;
 | 
			
		||||
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.TbResourceId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.dao.exception.DataValidationException;
 | 
			
		||||
@ -46,14 +48,12 @@ public class ResourceEdgeProcessor extends BaseResourceProcessor {
 | 
			
		||||
            switch (resourceUpdateMsg.getMsgType()) {
 | 
			
		||||
                case ENTITY_CREATED_RPC_MESSAGE:
 | 
			
		||||
                case ENTITY_UPDATED_RPC_MESSAGE:
 | 
			
		||||
                    super.saveOrUpdateTbResource(tenantId, tbResourceId, resourceUpdateMsg);
 | 
			
		||||
                    break;
 | 
			
		||||
                case ENTITY_DELETED_RPC_MESSAGE:
 | 
			
		||||
                    TbResource tbResourceToDelete = resourceService.findResourceById(tenantId, tbResourceId);
 | 
			
		||||
                    if (tbResourceToDelete != null) {
 | 
			
		||||
                        resourceService.deleteResource(tenantId, tbResourceId);
 | 
			
		||||
                    boolean resourceKeyUpdated = super.saveOrUpdateTbResource(tenantId, tbResourceId, resourceUpdateMsg);
 | 
			
		||||
                    if (resourceKeyUpdated) {
 | 
			
		||||
                        saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.TB_RESOURCE, EdgeEventActionType.UPDATED, tbResourceId, null);
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
                case ENTITY_DELETED_RPC_MESSAGE:
 | 
			
		||||
                case UNRECOGNIZED:
 | 
			
		||||
                    return handleUnsupportedMsgType(resourceUpdateMsg.getMsgType());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,36 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2023 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.edge.rpc.utils;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.thingsboard.server.gen.edge.v1.EdgeVersion;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
public final class EdgeVersionUtils {
 | 
			
		||||
 | 
			
		||||
    public static boolean isEdgeProtoDeprecated(EdgeVersion edgeVersion) {
 | 
			
		||||
        switch (edgeVersion) {
 | 
			
		||||
            case V_3_3_0:
 | 
			
		||||
            case V_3_3_3:
 | 
			
		||||
            case V_3_4_0:
 | 
			
		||||
            case V_3_6_0:
 | 
			
		||||
                return true;
 | 
			
		||||
            case V_3_6_1:
 | 
			
		||||
            default:
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -486,7 +486,7 @@ public class DefaultTbClusterService implements TbClusterService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action, EdgeId sourceEdgeId) {
 | 
			
		||||
    public void sendNotificationMsgToEdge(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action, EdgeId originatorEdgeId) {
 | 
			
		||||
        if (!edgesEnabled) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@ -519,9 +519,9 @@ public class DefaultTbClusterService implements TbClusterService {
 | 
			
		||||
        if (body != null) {
 | 
			
		||||
            builder.setBody(body);
 | 
			
		||||
        }
 | 
			
		||||
        if (sourceEdgeId != null) {
 | 
			
		||||
            builder.setSourceEdgeIdMSB(sourceEdgeId.getId().getMostSignificantBits());
 | 
			
		||||
            builder.setSourceEdgeIdLSB(sourceEdgeId.getId().getLeastSignificantBits());
 | 
			
		||||
        if (originatorEdgeId != null) {
 | 
			
		||||
            builder.setOriginatorEdgeIdMSB(originatorEdgeId.getId().getMostSignificantBits());
 | 
			
		||||
            builder.setOriginatorEdgeIdLSB(originatorEdgeId.getId().getLeastSignificantBits());
 | 
			
		||||
        }
 | 
			
		||||
        TransportProtos.EdgeNotificationMsgProto msg = builder.build();
 | 
			
		||||
        log.trace("[{}] sending notification to edge service {}", tenantId.getId(), msg);
 | 
			
		||||
 | 
			
		||||
@ -152,22 +152,29 @@ public class ProtoUtils {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static TransportProtos.DeviceEdgeUpdateMsgProto toProto(DeviceEdgeUpdateMsg msg) {
 | 
			
		||||
        return TransportProtos.DeviceEdgeUpdateMsgProto.newBuilder()
 | 
			
		||||
        TransportProtos.DeviceEdgeUpdateMsgProto.Builder builder = TransportProtos.DeviceEdgeUpdateMsgProto.newBuilder()
 | 
			
		||||
                .setTenantIdMSB(msg.getTenantId().getId().getMostSignificantBits())
 | 
			
		||||
                .setTenantIdLSB(msg.getTenantId().getId().getLeastSignificantBits())
 | 
			
		||||
                .setDeviceIdMSB(msg.getDeviceId().getId().getMostSignificantBits())
 | 
			
		||||
                .setDeviceIdLSB(msg.getDeviceId().getId().getLeastSignificantBits())
 | 
			
		||||
                .setEdgeIdMSB(msg.getEdgeId().getId().getMostSignificantBits())
 | 
			
		||||
                .setEdgeIdLSB(msg.getEdgeId().getId().getLeastSignificantBits())
 | 
			
		||||
                .build();
 | 
			
		||||
                .setDeviceIdLSB(msg.getDeviceId().getId().getLeastSignificantBits());
 | 
			
		||||
 | 
			
		||||
        if (msg.getEdgeId() != null) {
 | 
			
		||||
            builder.setEdgeIdMSB(msg.getEdgeId().getId().getMostSignificantBits())
 | 
			
		||||
                    .setEdgeIdLSB(msg.getEdgeId().getId().getLeastSignificantBits());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static DeviceEdgeUpdateMsg fromProto(TransportProtos.DeviceEdgeUpdateMsgProto proto) {
 | 
			
		||||
        EdgeId edgeId = null;
 | 
			
		||||
        if (proto.hasEdgeIdMSB() && proto.hasEdgeIdLSB()) {
 | 
			
		||||
            edgeId = new EdgeId(new UUID(proto.getEdgeIdMSB(), proto.getEdgeIdLSB()));
 | 
			
		||||
        }
 | 
			
		||||
        return new DeviceEdgeUpdateMsg(
 | 
			
		||||
                TenantId.fromUUID(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB())),
 | 
			
		||||
                new DeviceId(new UUID(proto.getDeviceIdMSB(), proto.getDeviceIdLSB())),
 | 
			
		||||
                new EdgeId(new UUID(proto.getEdgeIdMSB(), proto.getEdgeIdLSB()))
 | 
			
		||||
        );
 | 
			
		||||
                edgeId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static TransportProtos.DeviceNameOrTypeUpdateMsgProto toProto(DeviceNameOrTypeUpdateMsg msg) {
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageLink;
 | 
			
		||||
import org.thingsboard.server.common.data.security.Authority;
 | 
			
		||||
import org.thingsboard.server.common.data.security.model.JwtSettings;
 | 
			
		||||
import org.thingsboard.server.dao.edge.EdgeDao;
 | 
			
		||||
import org.thingsboard.server.dao.exception.DataValidationException;
 | 
			
		||||
import org.thingsboard.server.dao.model.ModelConstants;
 | 
			
		||||
@ -843,6 +844,13 @@ public class EdgeControllerTest extends AbstractControllerTest {
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSyncEdge() throws Exception {
 | 
			
		||||
        loginSysAdmin();
 | 
			
		||||
        // get jwt settings from yaml config
 | 
			
		||||
        JwtSettings settings = doGet("/api/admin/jwtSettings", JwtSettings.class);
 | 
			
		||||
        // save jwt settings into db
 | 
			
		||||
        doPost("/api/admin/jwtSettings", settings).andExpect(status().isOk());
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        Asset asset = new Asset();
 | 
			
		||||
        asset.setName("Test Sync Edge Asset 1");
 | 
			
		||||
        asset.setType("test");
 | 
			
		||||
@ -904,10 +912,10 @@ public class EdgeControllerTest extends AbstractControllerTest {
 | 
			
		||||
    private void verifyFetchersMsgs(EdgeImitator edgeImitator) {
 | 
			
		||||
        Assert.assertTrue(popQueueMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Main"));
 | 
			
		||||
        Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Edge Root Rule Chain"));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail", true));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail", false));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mailTemplates", true));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mailTemplates", false));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "general"));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "mail"));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "connectivity"));
 | 
			
		||||
        Assert.assertTrue(popAdminSettingsMsg(edgeImitator.getDownlinkMsgs(), "jwt"));
 | 
			
		||||
        Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default"));
 | 
			
		||||
        Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default"));
 | 
			
		||||
        Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default"));
 | 
			
		||||
@ -953,12 +961,11 @@ public class EdgeControllerTest extends AbstractControllerTest {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean popAdminSettingsMsg(List<AbstractMessage> messages, String key, boolean isSystem) {
 | 
			
		||||
    private boolean popAdminSettingsMsg(List<AbstractMessage> messages, String key) {
 | 
			
		||||
        for (AbstractMessage message : messages) {
 | 
			
		||||
            if (message instanceof AdminSettingsUpdateMsg) {
 | 
			
		||||
                AdminSettingsUpdateMsg adminSettingsUpdateMsg = (AdminSettingsUpdateMsg) message;
 | 
			
		||||
                if (key.equals(adminSettingsUpdateMsg.getKey())
 | 
			
		||||
                        && isSystem == adminSettingsUpdateMsg.getIsSystem()) {
 | 
			
		||||
                if (key.equals(adminSettingsUpdateMsg.getKey())) {
 | 
			
		||||
                    messages.remove(message);
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,7 @@ import org.thingsboard.server.common.data.query.NumericFilterPredicate;
 | 
			
		||||
import org.thingsboard.server.common.data.queue.Queue;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChain;
 | 
			
		||||
import org.thingsboard.server.common.data.rule.RuleChainType;
 | 
			
		||||
import org.thingsboard.server.common.data.security.model.JwtSettings;
 | 
			
		||||
import org.thingsboard.server.controller.AbstractControllerTest;
 | 
			
		||||
import org.thingsboard.server.dao.edge.EdgeEventService;
 | 
			
		||||
import org.thingsboard.server.edge.imitator.EdgeImitator;
 | 
			
		||||
@ -98,6 +99,7 @@ import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.TreeMap;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
 | 
			
		||||
@ -127,6 +129,13 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setupEdgeTest() throws Exception {
 | 
			
		||||
        loginSysAdmin();
 | 
			
		||||
 | 
			
		||||
        // get jwt settings from yaml config
 | 
			
		||||
        JwtSettings settings = doGet("/api/admin/jwtSettings", JwtSettings.class);
 | 
			
		||||
        // save jwt settings into db
 | 
			
		||||
        doPost("/api/admin/jwtSettings", settings).andExpect(status().isOk());
 | 
			
		||||
 | 
			
		||||
        loginTenantAdmin();
 | 
			
		||||
 | 
			
		||||
        installation();
 | 
			
		||||
@ -173,7 +182,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
        } catch (Exception ignored) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void installation() {
 | 
			
		||||
    private void installation() throws Exception {
 | 
			
		||||
        thermostatDeviceProfile = this.createDeviceProfile(THERMOSTAT_DEVICE_PROFILE_NAME,
 | 
			
		||||
                createMqttDeviceProfileTransportConfiguration(new JsonTransportPayloadConfiguration(), false));
 | 
			
		||||
        extendDeviceProfileData(thermostatDeviceProfile);
 | 
			
		||||
@ -189,6 +198,9 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
                + "/device/" + savedDevice.getUuidId(), Device.class);
 | 
			
		||||
        doPost("/api/edge/" + edge.getUuidId()
 | 
			
		||||
                + "/asset/" + savedAsset.getUuidId(), Asset.class);
 | 
			
		||||
 | 
			
		||||
        // wait until assign device and asset events are fully processed by edge notification service
 | 
			
		||||
        TimeUnit.MILLISECONDS.sleep(500);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected void extendDeviceProfileData(DeviceProfile deviceProfile) {
 | 
			
		||||
@ -237,25 +249,23 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
        validateMsgsCnt(RuleChainMetadataUpdateMsg.class, 1);
 | 
			
		||||
        validateRuleChainMetadataUpdates(ruleChainUUID);
 | 
			
		||||
 | 
			
		||||
        // 4 messages
 | 
			
		||||
        // - 2 from fetcher - system level ('mail', 'mailTemplates')
 | 
			
		||||
        // - 2 from fetcher - admin level ('mail', 'mailTemplates')
 | 
			
		||||
        // 4 messages ('general', 'mail', 'connectivity', 'jwt)
 | 
			
		||||
        validateMsgsCnt(AdminSettingsUpdateMsg.class, 4);
 | 
			
		||||
        validateAdminSettings();
 | 
			
		||||
        validateAdminSettings(4);
 | 
			
		||||
 | 
			
		||||
        // 4 messages
 | 
			
		||||
        // - 1 from default profile fetcher
 | 
			
		||||
        // - 2 from device profile fetcher (default and thermostat)
 | 
			
		||||
        // - 1 from device fetcher
 | 
			
		||||
        validateMsgsCnt(DeviceProfileUpdateMsg.class, 4);
 | 
			
		||||
        validateDeviceProfiles();
 | 
			
		||||
        validateDeviceProfiles(4);
 | 
			
		||||
 | 
			
		||||
        // 3 messages
 | 
			
		||||
        // - 1 from default profile fetcher
 | 
			
		||||
        // - 1 message from asset profile fetcher
 | 
			
		||||
        // - 1 message from asset fetcher
 | 
			
		||||
        validateMsgsCnt(AssetProfileUpdateMsg.class, 3);
 | 
			
		||||
        validateAssetProfiles();
 | 
			
		||||
        validateAssetProfiles(3);
 | 
			
		||||
 | 
			
		||||
        // 1 from device fetcher
 | 
			
		||||
        validateMsgsCnt(DeviceUpdateMsg.class, 1);
 | 
			
		||||
@ -326,13 +336,13 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
        testAutoGeneratedCodeByProtobuf(tenantProfileUpdateMsg);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateDeviceProfiles() throws Exception {
 | 
			
		||||
    private void validateDeviceProfiles(int expectedMsgCnt) throws Exception {
 | 
			
		||||
        List<DeviceProfileUpdateMsg> deviceProfileUpdateMsgList = edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class);
 | 
			
		||||
        // default msg default device profile from fetcher
 | 
			
		||||
        // default msg device profile from fetcher
 | 
			
		||||
        // thermostat msg from device profile fetcher
 | 
			
		||||
        // thermostat msg from device fetcher
 | 
			
		||||
        Assert.assertEquals(4, deviceProfileUpdateMsgList.size());
 | 
			
		||||
        Assert.assertEquals(expectedMsgCnt, deviceProfileUpdateMsgList.size());
 | 
			
		||||
        Optional<DeviceProfileUpdateMsg> thermostatProfileUpdateMsgOpt =
 | 
			
		||||
                deviceProfileUpdateMsgList.stream().filter(dfum -> THERMOSTAT_DEVICE_PROFILE_NAME.equals(dfum.getName())).findAny();
 | 
			
		||||
        Assert.assertTrue(thermostatProfileUpdateMsgOpt.isPresent());
 | 
			
		||||
@ -413,20 +423,28 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertEquals(expectedRuleChainUUID, ruleChainUUID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateAdminSettings() {
 | 
			
		||||
    private void validateAdminSettings(int expectedMsgCnt) {
 | 
			
		||||
        List<AdminSettingsUpdateMsg> adminSettingsUpdateMsgs = edgeImitator.findAllMessagesByType(AdminSettingsUpdateMsg.class);
 | 
			
		||||
        Assert.assertEquals(4, adminSettingsUpdateMsgs.size());
 | 
			
		||||
        Assert.assertEquals(expectedMsgCnt, adminSettingsUpdateMsgs.size());
 | 
			
		||||
 | 
			
		||||
        for (AdminSettingsUpdateMsg adminSettingsUpdateMsg : adminSettingsUpdateMsgs) {
 | 
			
		||||
            if (adminSettingsUpdateMsg.getKey().equals("general")) {
 | 
			
		||||
                validateGeneralAdminSettings(adminSettingsUpdateMsg);
 | 
			
		||||
            }
 | 
			
		||||
            if (adminSettingsUpdateMsg.getKey().equals("mail")) {
 | 
			
		||||
                validateMailAdminSettings(adminSettingsUpdateMsg);
 | 
			
		||||
            }
 | 
			
		||||
            if (adminSettingsUpdateMsg.getKey().equals("mailTemplates")) {
 | 
			
		||||
                validateMailTemplatesAdminSettings(adminSettingsUpdateMsg);
 | 
			
		||||
            if (adminSettingsUpdateMsg.getKey().equals("connectivity")) {
 | 
			
		||||
                validateConnectivityAdminSettings(adminSettingsUpdateMsg);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateGeneralAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
 | 
			
		||||
        JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue());
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("baseUrl"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateMailAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
 | 
			
		||||
        JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue());
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("mailFrom"));
 | 
			
		||||
@ -436,19 +454,19 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest {
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("timeout"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateMailTemplatesAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
 | 
			
		||||
    private void validateConnectivityAdminSettings(AdminSettingsUpdateMsg adminSettingsUpdateMsg) {
 | 
			
		||||
        JsonNode jsonNode = JacksonUtil.toJsonNode(adminSettingsUpdateMsg.getJsonValue());
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("accountActivated"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("accountLockout"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("activation"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("passwordWasReset"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("resetPassword"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("test"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("http"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("https"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("mqtt"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("mqtts"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("coap"));
 | 
			
		||||
        Assert.assertNotNull(jsonNode.get("coaps"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateAssetProfiles() throws Exception {
 | 
			
		||||
    private void validateAssetProfiles(int expectedMsgCnt) throws Exception {
 | 
			
		||||
        List<AssetProfileUpdateMsg> assetProfileUpdateMsgs = edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class);
 | 
			
		||||
        Assert.assertEquals(3, assetProfileUpdateMsgs.size());
 | 
			
		||||
        Assert.assertEquals(expectedMsgCnt, assetProfileUpdateMsgs.size());
 | 
			
		||||
        AssetProfileUpdateMsg assetProfileUpdateMsg = assetProfileUpdateMsgs.get(0);
 | 
			
		||||
        Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, assetProfileUpdateMsg.getMsgType());
 | 
			
		||||
        UUID assetProfileUUID = new UUID(assetProfileUpdateMsg.getIdMSB(), assetProfileUpdateMsg.getIdLSB());
 | 
			
		||||
 | 
			
		||||
@ -173,7 +173,7 @@ public class AssetEdgeTest extends AbstractEdgeTest {
 | 
			
		||||
        assetUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
 | 
			
		||||
        assetUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
 | 
			
		||||
        assetUpdateMsgBuilder.setName("Asset Edge 2");
 | 
			
		||||
        assetUpdateMsgBuilder.setType("test");
 | 
			
		||||
        assetUpdateMsgBuilder.setType("default");
 | 
			
		||||
        assetUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
 | 
			
		||||
        testAutoGeneratedCodeByProtobuf(assetUpdateMsgBuilder);
 | 
			
		||||
        uplinkMsgBuilder.addAssetUpdateMsg(assetUpdateMsgBuilder.build());
 | 
			
		||||
@ -205,7 +205,7 @@ public class AssetEdgeTest extends AbstractEdgeTest {
 | 
			
		||||
        assetUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
 | 
			
		||||
        assetUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
 | 
			
		||||
        assetUpdateMsgBuilder.setName(assetOnCloudName);
 | 
			
		||||
        assetUpdateMsgBuilder.setType("test");
 | 
			
		||||
        assetUpdateMsgBuilder.setType("default");
 | 
			
		||||
        assetUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
 | 
			
		||||
        testAutoGeneratedCodeByProtobuf(assetUpdateMsgBuilder);
 | 
			
		||||
        uplinkMsgBuilder.addAssetUpdateMsg(assetUpdateMsgBuilder.build());
 | 
			
		||||
 | 
			
		||||
@ -492,7 +492,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
 | 
			
		||||
        deviceUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
 | 
			
		||||
        deviceUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
 | 
			
		||||
        deviceUpdateMsgBuilder.setName(deviceOnCloudName);
 | 
			
		||||
        deviceUpdateMsgBuilder.setType("test");
 | 
			
		||||
        deviceUpdateMsgBuilder.setType("default");
 | 
			
		||||
        deviceUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
 | 
			
		||||
        testAutoGeneratedCodeByProtobuf(deviceUpdateMsgBuilder);
 | 
			
		||||
        uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build());
 | 
			
		||||
@ -541,7 +541,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
 | 
			
		||||
        deviceUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
 | 
			
		||||
        deviceUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
 | 
			
		||||
        deviceUpdateMsgBuilder.setName("Edge Device 2");
 | 
			
		||||
        deviceUpdateMsgBuilder.setType("test");
 | 
			
		||||
        deviceUpdateMsgBuilder.setType("default");
 | 
			
		||||
        deviceUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
 | 
			
		||||
        uplinkMsgBuilder.addDeviceUpdateMsg(deviceUpdateMsgBuilder.build());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
 | 
			
		||||
import org.thingsboard.server.gen.edge.v1.UplinkMsg;
 | 
			
		||||
import org.thingsboard.server.gen.edge.v1.UplinkResponseMsg;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 | 
			
		||||
@ -120,4 +121,54 @@ public class ResourceEdgeTest extends AbstractEdgeTest {
 | 
			
		||||
        Assert.assertNotNull(tbResource);
 | 
			
		||||
        Assert.assertEquals("Edge Test Resource", tbResource.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testResourceToCloudWithNameThatAlreadyExistsOnCloud() throws Exception {
 | 
			
		||||
        TbResource resource = new TbResource();
 | 
			
		||||
        resource.setResourceType(ResourceType.JKS);
 | 
			
		||||
        resource.setTitle("Edge Test Resource");
 | 
			
		||||
        resource.setFileName(FILE_NAME);
 | 
			
		||||
        resource.setData(TEST_DATA);
 | 
			
		||||
 | 
			
		||||
        edgeImitator.expectMessageAmount(1);
 | 
			
		||||
        TbResource savedResource = doPost("/api/resource", resource, TbResource.class);
 | 
			
		||||
        Assert.assertTrue(edgeImitator.waitForMessages());
 | 
			
		||||
 | 
			
		||||
        UUID uuid = Uuids.timeBased();
 | 
			
		||||
 | 
			
		||||
        UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
 | 
			
		||||
        ResourceUpdateMsg.Builder resourceUpdateMsgBuilder = ResourceUpdateMsg.newBuilder();
 | 
			
		||||
        resourceUpdateMsgBuilder.setIdMSB(uuid.getMostSignificantBits());
 | 
			
		||||
        resourceUpdateMsgBuilder.setIdLSB(uuid.getLeastSignificantBits());
 | 
			
		||||
        resourceUpdateMsgBuilder.setTitle("Edge Test Resource");
 | 
			
		||||
        resourceUpdateMsgBuilder.setResourceType(ResourceType.JKS.name());
 | 
			
		||||
        resourceUpdateMsgBuilder.setResourceKey(FILE_NAME);
 | 
			
		||||
        resourceUpdateMsgBuilder.setFileName(FILE_NAME);
 | 
			
		||||
        resourceUpdateMsgBuilder.setData(TEST_DATA);
 | 
			
		||||
        resourceUpdateMsgBuilder.setIsSystem(false);
 | 
			
		||||
        resourceUpdateMsgBuilder.setMsgType(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE);
 | 
			
		||||
        testAutoGeneratedCodeByProtobuf(resourceUpdateMsgBuilder);
 | 
			
		||||
        uplinkMsgBuilder.addResourceUpdateMsg(resourceUpdateMsgBuilder.build());
 | 
			
		||||
 | 
			
		||||
        testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder);
 | 
			
		||||
 | 
			
		||||
        edgeImitator.expectResponsesAmount(1);
 | 
			
		||||
        edgeImitator.expectMessageAmount(1);
 | 
			
		||||
 | 
			
		||||
        edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
 | 
			
		||||
 | 
			
		||||
        Assert.assertTrue(edgeImitator.waitForResponses());
 | 
			
		||||
        Assert.assertTrue(edgeImitator.waitForMessages());
 | 
			
		||||
 | 
			
		||||
        Optional<ResourceUpdateMsg> resourceUpdateMsgOpt = edgeImitator.findMessageByType(ResourceUpdateMsg.class);
 | 
			
		||||
        Assert.assertTrue(resourceUpdateMsgOpt.isPresent());
 | 
			
		||||
        ResourceUpdateMsg latestResourceUpdateMsg = resourceUpdateMsgOpt.get();
 | 
			
		||||
        Assert.assertNotEquals(FILE_NAME, latestResourceUpdateMsg.getResourceKey());
 | 
			
		||||
 | 
			
		||||
        Assert.assertNotEquals(savedResource.getUuidId(), uuid);
 | 
			
		||||
 | 
			
		||||
        TbResource tbResource = doGet("/api/resource/" + uuid, TbResource.class);
 | 
			
		||||
        Assert.assertNotNull(tbResource);
 | 
			
		||||
        Assert.assertNotEquals(FILE_NAME, tbResource.getName());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -910,8 +910,8 @@ message EdgeNotificationMsgProto {
 | 
			
		||||
  string body = 10;
 | 
			
		||||
  PostTelemetryMsg postTelemetryMsg = 11;
 | 
			
		||||
  PostAttributeMsg postAttributesMsg = 12;
 | 
			
		||||
  int64 sourceEdgeIdMSB = 13;
 | 
			
		||||
  int64 sourceEdgeIdLSB = 14;
 | 
			
		||||
  int64 originatorEdgeIdMSB = 13;
 | 
			
		||||
  int64 originatorEdgeIdLSB = 14;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message EdgeEventUpdateMsgProto {
 | 
			
		||||
@ -945,8 +945,8 @@ message DeviceEdgeUpdateMsgProto {
 | 
			
		||||
  int64 tenantIdLSB = 2;
 | 
			
		||||
  int64 deviceIdMSB = 3;
 | 
			
		||||
  int64 deviceIdLSB = 4;
 | 
			
		||||
  int64 edgeIdMSB = 5;
 | 
			
		||||
  int64 edgeIdLSB = 6;
 | 
			
		||||
  optional int64 edgeIdMSB = 5;
 | 
			
		||||
  optional int64 edgeIdLSB = 6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message DeviceNameOrTypeUpdateMsgProto {
 | 
			
		||||
 | 
			
		||||
@ -111,7 +111,7 @@ public class EdgeGrpcClient implements EdgeRpcClient {
 | 
			
		||||
                .setConnectRequestMsg(ConnectRequestMsg.newBuilder()
 | 
			
		||||
                        .setEdgeRoutingKey(edgeKey)
 | 
			
		||||
                        .setEdgeSecret(edgeSecret)
 | 
			
		||||
                        .setEdgeVersion(EdgeVersion.V_3_6_0)
 | 
			
		||||
                        .setEdgeVersion(EdgeVersion.V_3_6_1)
 | 
			
		||||
                        .setMaxInboundMessageSize(maxInboundMessageSize)
 | 
			
		||||
                        .build())
 | 
			
		||||
                .build());
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,7 @@ enum EdgeVersion {
 | 
			
		||||
  V_3_3_3 = 1;
 | 
			
		||||
  V_3_4_0 = 2;
 | 
			
		||||
  V_3_6_0 = 3;
 | 
			
		||||
  V_3_6_1 = 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -361,8 +362,8 @@ message WidgetsBundleUpdateMsg {
 | 
			
		||||
  optional bytes image = 6;
 | 
			
		||||
  bool isSystem = 7;
 | 
			
		||||
  optional string description = 8;
 | 
			
		||||
  optional int32 order = 9;
 | 
			
		||||
  optional string widgets = 10;
 | 
			
		||||
  optional string widgets = 9;
 | 
			
		||||
  optional int32 order = 10;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message WidgetTypeUpdateMsg {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user