Use output rule node name instead of label
This commit is contained in:
		
							parent
							
								
									65fb622b21
								
							
						
					
					
						commit
						b5da8752c5
					
				@ -36,10 +36,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
import org.springframework.web.bind.annotation.ResponseBody;
 | 
			
		||||
import org.springframework.web.bind.annotation.ResponseStatus;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.rule.engine.api.ScriptEngine;
 | 
			
		||||
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode;
 | 
			
		||||
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration;
 | 
			
		||||
import org.thingsboard.server.actors.ActorSystemContext;
 | 
			
		||||
import org.thingsboard.server.actors.tenant.DebugTbRateLimits;
 | 
			
		||||
import org.thingsboard.server.common.data.DataConstants;
 | 
			
		||||
@ -71,7 +68,6 @@ import org.thingsboard.server.common.msg.TbMsg;
 | 
			
		||||
import org.thingsboard.server.common.msg.TbMsgDataType;
 | 
			
		||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
 | 
			
		||||
import org.thingsboard.server.dao.event.EventService;
 | 
			
		||||
import org.thingsboard.server.dao.rule.RuleChainService;
 | 
			
		||||
import org.thingsboard.server.queue.util.TbCoreComponent;
 | 
			
		||||
import org.thingsboard.server.service.install.InstallScripts;
 | 
			
		||||
import org.thingsboard.server.service.rule.TbRuleChainService;
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,6 @@ import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNode;
 | 
			
		||||
import org.thingsboard.rule.engine.flow.TbRuleChainInputNodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNode;
 | 
			
		||||
import org.thingsboard.rule.engine.flow.TbRuleChainOutputNodeConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.StringUtils;
 | 
			
		||||
import org.thingsboard.server.common.data.id.RuleChainId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.RuleNodeId;
 | 
			
		||||
@ -65,14 +64,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService {
 | 
			
		||||
        Set<String> outputLabels = new TreeSet<>();
 | 
			
		||||
        for (RuleNode ruleNode : metaData.getNodes()) {
 | 
			
		||||
            if (isOutputRuleNode(ruleNode)) {
 | 
			
		||||
                try {
 | 
			
		||||
                    var configuration = JacksonUtil.treeToValue(ruleNode.getConfiguration(), TbRuleChainOutputNodeConfiguration.class);
 | 
			
		||||
                    if (StringUtils.isNotEmpty(configuration.getLabel())) {
 | 
			
		||||
                        outputLabels.add(configuration.getLabel());
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    log.warn("[{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, e);
 | 
			
		||||
                }
 | 
			
		||||
                outputLabels.add(ruleNode.getName());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return outputLabels;
 | 
			
		||||
@ -130,16 +122,15 @@ public class DefaultTbRuleChainService implements TbRuleChainService {
 | 
			
		||||
        Set<String> confusedLabels = new HashSet<>();
 | 
			
		||||
        Map<String, String> updatedLabels = new HashMap<>();
 | 
			
		||||
        for (RuleNodeUpdateResult update : result.getUpdatedRuleNodes()) {
 | 
			
		||||
            var node = update.getNewRuleNode();
 | 
			
		||||
            if (isOutputRuleNode(node)) {
 | 
			
		||||
            var oldNode = update.getOldRuleNode();
 | 
			
		||||
            var newNode = update.getNewRuleNode();
 | 
			
		||||
            if (isOutputRuleNode(newNode)) {
 | 
			
		||||
                try {
 | 
			
		||||
                    TbRuleChainOutputNodeConfiguration oldConf = JacksonUtil.treeToValue(update.getOldConfiguration(), TbRuleChainOutputNodeConfiguration.class);
 | 
			
		||||
                    TbRuleChainOutputNodeConfiguration newConf = JacksonUtil.treeToValue(node.getConfiguration(), TbRuleChainOutputNodeConfiguration.class);
 | 
			
		||||
                    oldLabels.add(oldConf.getLabel());
 | 
			
		||||
                    newLabels.add(newConf.getLabel());
 | 
			
		||||
                    if (!oldConf.getLabel().equals(newConf.getLabel())) {
 | 
			
		||||
                        String oldLabel = oldConf.getLabel();
 | 
			
		||||
                        String newLabel = newConf.getLabel();
 | 
			
		||||
                    oldLabels.add(oldNode.getName());
 | 
			
		||||
                    newLabels.add(newNode.getName());
 | 
			
		||||
                    if (!oldNode.getName().equals(newNode.getName())) {
 | 
			
		||||
                        String oldLabel = oldNode.getName();
 | 
			
		||||
                        String newLabel = newNode.getName();
 | 
			
		||||
                        if (updatedLabels.containsKey(oldLabel) && !updatedLabels.get(oldLabel).equals(newLabel)) {
 | 
			
		||||
                            confusedLabels.add(oldLabel);
 | 
			
		||||
                            log.warn("[{}][{}] Can't automatically rename the label from [{}] to [{}] due to conflict [{}]", tenantId, ruleChainId, oldLabel, newLabel, updatedLabels.get(oldLabel));
 | 
			
		||||
@ -149,7 +140,7 @@ public class DefaultTbRuleChainService implements TbRuleChainService {
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, node.getId(), e);
 | 
			
		||||
                    log.warn("[{}][{}][{}] Failed to decode rule node configuration", tenantId, ruleChainId, newNode.getId(), e);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ import java.util.Map;
 | 
			
		||||
@Data
 | 
			
		||||
public class RuleNodeUpdateResult {
 | 
			
		||||
 | 
			
		||||
    private final JsonNode oldConfiguration;
 | 
			
		||||
    private final RuleNode oldRuleNode;
 | 
			
		||||
    private final RuleNode newRuleNode;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -172,10 +172,10 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
 | 
			
		||||
                newRuleNode = ruleChainMetaData.getNodes().get(index);
 | 
			
		||||
                toAddOrUpdate.add(newRuleNode);
 | 
			
		||||
            } else {
 | 
			
		||||
                updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), null));
 | 
			
		||||
                updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, null));
 | 
			
		||||
                toDelete.add(existingNode);
 | 
			
		||||
            }
 | 
			
		||||
            updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode.getConfiguration(), newRuleNode));
 | 
			
		||||
            updatedRuleNodes.add(new RuleNodeUpdateResult(existingNode, newRuleNode));
 | 
			
		||||
        }
 | 
			
		||||
        if (nodes != null) {
 | 
			
		||||
            for (RuleNode node : toAddOrUpdate) {
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,7 @@
 | 
			
		||||
package org.thingsboard.rule.engine.flow;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.api.RuleNode;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbContext;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNode;
 | 
			
		||||
@ -30,28 +31,24 @@ import org.thingsboard.server.common.msg.TbMsg;
 | 
			
		||||
@RuleNode(
 | 
			
		||||
        type = ComponentType.FLOW,
 | 
			
		||||
        name = "output",
 | 
			
		||||
        configClazz = TbRuleChainOutputNodeConfiguration.class,
 | 
			
		||||
        configClazz = EmptyNodeConfiguration.class,
 | 
			
		||||
        nodeDescription = "transfers the message to the caller rule chain",
 | 
			
		||||
        nodeDetails = "Produces output of the rule chain processing. " +
 | 
			
		||||
                "The output is forwarded to the caller rule chain, as an output of the corresponding \"input\" rule node. " +
 | 
			
		||||
                "The rule node configuration contains the \"label\" parameter. " +
 | 
			
		||||
                "This parameter corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ",
 | 
			
		||||
                "The output rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain. ",
 | 
			
		||||
        uiResources = {"static/rulenode/rulenode-core-config.js"},
 | 
			
		||||
        configDirective = "tbFlowNodeRuleChainOutputConfig",
 | 
			
		||||
        outEnabled = false
 | 
			
		||||
)
 | 
			
		||||
public class TbRuleChainOutputNode implements TbNode {
 | 
			
		||||
 | 
			
		||||
    private TbRuleChainOutputNodeConfiguration config;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
 | 
			
		||||
        this.config = TbNodeUtils.convert(configuration, TbRuleChainOutputNodeConfiguration.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMsg(TbContext ctx, TbMsg msg) {
 | 
			
		||||
        ctx.output(msg, config.getLabel());
 | 
			
		||||
        ctx.output(msg, ctx.getSelf().getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2021 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.rule.engine.flow;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbRelationTypes;
 | 
			
		||||
import org.thingsboard.server.common.data.DataConstants;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class TbRuleChainOutputNodeConfiguration implements NodeConfiguration<TbRuleChainOutputNodeConfiguration> {
 | 
			
		||||
 | 
			
		||||
    private String label;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public TbRuleChainOutputNodeConfiguration defaultConfiguration() {
 | 
			
		||||
        var result = new TbRuleChainOutputNodeConfiguration();
 | 
			
		||||
        result.setLabel(TbRelationTypes.SUCCESS);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -3728,13 +3728,11 @@ class RuleChainOutputComponent extends RuleNodeConfigurationComponent {
 | 
			
		||||
        return this.ruleChainOutputConfigForm;
 | 
			
		||||
    }
 | 
			
		||||
    onConfigurationSet(configuration) {
 | 
			
		||||
        this.ruleChainOutputConfigForm = this.fb.group({
 | 
			
		||||
            label: [configuration ? configuration.label : null, [Validators.required]]
 | 
			
		||||
        });
 | 
			
		||||
        this.ruleChainOutputConfigForm = this.fb.group({});
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
RuleChainOutputComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, deps: [{ token: i1.Store }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
 | 
			
		||||
RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "<section [formGroup]=\"ruleChainOutputConfigForm\" fxLayout=\"column\">\n  <mat-form-field class=\"mat-block\">\n    <mat-label translate>tb.rulenode.label</mat-label>\n    <input required matInput formControlName=\"label\">\n    <mat-error *ngIf=\"ruleChainOutputConfigForm.get('label').hasError('required')\">\n      {{ 'tb.rulenode.label-required' | translate }}\n    </mat-error>\n  </mat-form-field>\n</section>\n", components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "floatLabel", "appearance", "hideRequiredMarker", "hintLabel"], exportAs: ["matFormField"] }], directives: [{ type: i8.DefaultLayoutDirective, selector: "  [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md],  [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md],  [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm],  [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i4.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { type: i11.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl],      input[matNativeControl], textarea[matNativeControl]", inputs: ["id", "disabled", "required", "type", "value", "readonly", "placeholder", "errorStateMatcher", "aria-describedby"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i10.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }], pipes: { "translate": i4.TranslatePipe } });
 | 
			
		||||
RuleChainOutputComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.14", type: RuleChainOutputComponent, selector: "tb-flow-node-rule-chain-output-config", usesInheritance: true, ngImport: i0, template: "<section [formGroup]=\"ruleChainOutputConfigForm\" fxLayout=\"column\">\n  <div innerHTML=\"{{ 'tb.rulenode.output-node-name-hint' | translate }}\"></div>\n</section>\n", directives: [{ type: i8.DefaultLayoutDirective, selector: "  [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md],  [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md],  [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm],  [fxLayout.gt-md], [fxLayout.gt-lg]", inputs: ["fxLayout", "fxLayout.xs", "fxLayout.sm", "fxLayout.md", "fxLayout.lg", "fxLayout.xl", "fxLayout.lt-sm", "fxLayout.lt-md", "fxLayout.lt-lg", "fxLayout.lt-xl", "fxLayout.gt-xs", "fxLayout.gt-sm", "fxLayout.gt-md", "fxLayout.gt-lg"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], pipes: { "translate": i4.TranslatePipe } });
 | 
			
		||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.14", ngImport: i0, type: RuleChainOutputComponent, decorators: [{
 | 
			
		||||
            type: Component,
 | 
			
		||||
            args: [{
 | 
			
		||||
@ -4191,8 +4189,7 @@ function addRuleNodeCoreLocaleEnglish(translate) {
 | 
			
		||||
                'alarm-severity-pattern-hint': 'Hint: use <code><span style="color: #000;">${</span>metadataKey<span style="color: #000;">}</span></code> ' +
 | 
			
		||||
                    'for value from metadata, <code><span style="color: #000;">$[</span>messageKey<span style="color: #000;">]</span></code> ' +
 | 
			
		||||
                    'for value from message body. Alarm severity should be system (CRITICAL, MAJOR etc.)',
 | 
			
		||||
                label: 'Label',
 | 
			
		||||
                'label-required': 'Label is required'
 | 
			
		||||
                'output-node-name-hint': 'The <b>rule node name</b> corresponds to the <b>relation type</b> of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.'
 | 
			
		||||
            },
 | 
			
		||||
            'key-val': {
 | 
			
		||||
                key: 'Key',
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user