From 8f3fbc945dd7c33c1eb1305e499e07725d2c0570 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 22 Mar 2018 13:16:28 +0200 Subject: [PATCH] RuleNode annotation refactoring --- .../AnnotationComponentDiscoveryService.java | 90 ++++++++++++------- .../rule/engine/api/ActionNode.java | 43 --------- .../rule/engine/api/EnrichmentNode.java | 49 ---------- .../rule/engine/api/NodeDefinition.java | 33 +++++++ .../api/{FilterNode.java => RuleNode.java} | 11 ++- .../rule/engine/api/TransformationNode.java | 51 ----------- .../src/main/resources/EmptyNodeConfig.json | 2 + .../rule/engine/filter/TbJsFilterNode.java | 11 ++- .../rule/engine/filter/TbJsSwitchNode.java | 9 +- .../engine/filter/TbMsgTypeFilterNode.java | 7 +- .../engine/metadata/TbGetAttributesNode.java | 12 +-- .../metadata/TbGetCustomerAttributeNode.java | 9 +- .../metadata/TbGetRelatedAttributeNode.java | 13 ++- .../metadata/TbGetTenantAttributeNode.java | 9 +- .../transform/TbChangeOriginatorNode.java | 5 +- .../engine/transform/TbTransformMsgNode.java | 11 ++- ui/src/app/common/types.constant.js | 15 +++- ui/src/app/rulechain/rulechain.controller.js | 3 +- ui/src/app/rulechain/rulechain.scss | 29 ++++++ 19 files changed, 194 insertions(+), 218 deletions(-) delete mode 100644 rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java delete mode 100644 rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java create mode 100644 rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java rename rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/{FilterNode.java => RuleNode.java} (87%) delete mode 100644 rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java create mode 100644 rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json diff --git a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java index d9416d7226..52d7d7d80c 100644 --- a/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java +++ b/application/src/main/java/org/thingsboard/server/service/component/AnnotationComponentDiscoveryService.java @@ -16,6 +16,8 @@ package org.thingsboard.server.service.component; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.JsonNode; import com.google.common.base.Charsets; import com.google.common.io.Resources; import lombok.extern.slf4j.Slf4j; @@ -26,16 +28,14 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen import org.springframework.core.env.Environment; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.stereotype.Service; -import org.thingsboard.rule.engine.api.ActionNode; -import org.thingsboard.rule.engine.api.EnrichmentNode; -import org.thingsboard.rule.engine.api.FilterNode; -import org.thingsboard.rule.engine.api.TransformationNode; +import org.thingsboard.rule.engine.api.*; import org.thingsboard.server.common.data.plugin.ComponentDescriptor; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.dao.component.ComponentDescriptorService; import org.thingsboard.server.extensions.api.component.*; import javax.annotation.PostConstruct; +import java.io.IOException; import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; @@ -70,6 +70,24 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe } } + private void registerRuleNodeComponents() { + Set ruleNodeBeanDefinitions = getBeanDefinitions(RuleNode.class); + for (BeanDefinition def : ruleNodeBeanDefinitions) { + try { + String clazzName = def.getBeanClassName(); + Class clazz = Class.forName(clazzName); + RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); + ComponentType type = ruleNodeAnnotation.type(); + ComponentDescriptor component = scanAndPersistComponent(def, type); + components.put(component.getClazz(), component); + componentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); + } catch (Exception e) { + log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); + throw new RuntimeException(e); + } + } + } + private void registerComponents(ComponentType type, Class annotation) { List components = persist(getBeanDefinitions(annotation), type); componentsMap.put(type, components); @@ -97,34 +115,25 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe String descriptorResourceName; switch (type) { case ENRICHMENT: - EnrichmentNode enrichmentAnnotation = clazz.getAnnotation(EnrichmentNode.class); - scannedComponent.setName(enrichmentAnnotation.name()); - scannedComponent.setScope(enrichmentAnnotation.scope()); - descriptorResourceName = enrichmentAnnotation.descriptor(); - break; case FILTER: - FilterNode filterAnnotation = clazz.getAnnotation(FilterNode.class); - scannedComponent.setName(filterAnnotation.name()); - scannedComponent.setScope(filterAnnotation.scope()); - descriptorResourceName = filterAnnotation.descriptor(); - break; case TRANSFORMATION: - TransformationNode trAnnotation = clazz.getAnnotation(TransformationNode.class); - scannedComponent.setName(trAnnotation.name()); - scannedComponent.setScope(trAnnotation.scope()); - descriptorResourceName = trAnnotation.descriptor(); - break; case ACTION: - ActionNode actionAnnotation = clazz.getAnnotation(ActionNode.class); - scannedComponent.setName(actionAnnotation.name()); - scannedComponent.setScope(actionAnnotation.scope()); - descriptorResourceName = actionAnnotation.descriptor(); + RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); + scannedComponent.setName(ruleNodeAnnotation.name()); + scannedComponent.setScope(ruleNodeAnnotation.scope()); + NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); + ObjectNode configurationDescriptor = mapper.createObjectNode(); + JsonNode node = mapper.valueToTree(nodeDefinition); + configurationDescriptor.set("nodeDefinition", node); + scannedComponent.setConfigurationDescriptor(configurationDescriptor); break; case OLD_ACTION: Action oldActionAnnotation = clazz.getAnnotation(Action.class); scannedComponent.setName(oldActionAnnotation.name()); scannedComponent.setScope(oldActionAnnotation.scope()); descriptorResourceName = oldActionAnnotation.descriptor(); + scannedComponent.setConfigurationDescriptor(mapper.readTree( + Resources.toString(Resources.getResource(descriptorResourceName), Charsets.UTF_8))); break; case PLUGIN: Plugin pluginAnnotation = clazz.getAnnotation(Plugin.class); @@ -143,12 +152,12 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe } } scannedComponent.setActions(Arrays.stream(pluginAnnotation.actions()).map(Class::getName).collect(Collectors.joining(","))); + scannedComponent.setConfigurationDescriptor(mapper.readTree( + Resources.toString(Resources.getResource(descriptorResourceName), Charsets.UTF_8))); break; default: throw new RuntimeException(type + " is not supported yet!"); } - scannedComponent.setConfigurationDescriptor(mapper.readTree( - Resources.toString(Resources.getResource(descriptorResourceName), Charsets.UTF_8))); scannedComponent.setClazz(clazzName); log.info("Processing scanned component: {}", scannedComponent); } catch (Exception e) { @@ -171,6 +180,20 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe return scannedComponent; } + private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws IOException { + NodeDefinition nodeDefinition = new NodeDefinition(); + nodeDefinition.setDetails(nodeAnnotation.nodeDetails()); + nodeDefinition.setDescription(nodeAnnotation.nodeDescription()); + nodeDefinition.setInEnabled(nodeAnnotation.inEnabled()); + nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled()); + nodeDefinition.setRelationTypes(nodeAnnotation.relationTypes()); + nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); + String defaultConfigResourceName = nodeAnnotation.defaultConfigResource(); + nodeDefinition.setDefaultConfiguration(mapper.readTree( + Resources.toString(Resources.getResource(defaultConfigResourceName), Charsets.UTF_8))); + return nodeDefinition; + } + private Set getBeanDefinitions(Class componentType) { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(componentType)); @@ -183,13 +206,8 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @Override public void discoverComponents() { - registerComponents(ComponentType.ENRICHMENT, EnrichmentNode.class); - - registerComponents(ComponentType.FILTER, FilterNode.class); - - registerComponents(ComponentType.TRANSFORMATION, TransformationNode.class); - registerComponents(ComponentType.ACTION, ActionNode.class); + registerRuleNodeComponents(); registerComponents(ComponentType.OLD_ACTION, Action.class); @@ -200,15 +218,19 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe @Override public List getComponents(ComponentType type) { - return Collections.unmodifiableList(componentsMap.get(type)); + if (componentsMap.containsKey(type)) { + return Collections.unmodifiableList(componentsMap.get(type)); + } else { + return Collections.emptyList(); + } } @Override public List getComponents(Set types) { List result = new ArrayList<>(); - for (ComponentType type : types) { + types.stream().filter(type -> componentsMap.containsKey(type)).forEach(type -> { result.addAll(componentsMap.get(type)); - } + }); return Collections.unmodifiableList(result); } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java deleted file mode 100644 index 64e28f1bf2..0000000000 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright © 2016-2018 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.api; - -import org.thingsboard.server.common.data.plugin.ComponentScope; -import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author Andrew Shvayka - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface ActionNode { - - String name(); - - ComponentScope scope() default ComponentScope.TENANT; - - String descriptor() default "EmptyNodeDescriptor.json"; - - String[] relationTypes() default {"Success","Failure"}; - - boolean customRelations() default false; - -} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java deleted file mode 100644 index b3ff2559eb..0000000000 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright © 2016-2018 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.api; - -import org.thingsboard.server.common.data.plugin.ComponentScope; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author Andrew Shvayka - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface EnrichmentNode { - - String name(); - - String nodeDescription(); - - String nodeDetails(); - - boolean inEnabled() default true; - - boolean outEnabled() default true; - - ComponentScope scope() default ComponentScope.TENANT; - - String descriptor() default "EmptyNodeDescriptor.json"; - - String[] relationTypes() default {"Success", "Failure"}; - - boolean customRelations() default false; -} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java new file mode 100644 index 0000000000..6c57d92a54 --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java @@ -0,0 +1,33 @@ +/** + * Copyright © 2016-2018 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.api; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Data; + +@Data +public class NodeDefinition { + + private String details; + private String description; + private boolean inEnabled; + private boolean outEnabled; + String[] relationTypes; + boolean customRelations; + JsonNode defaultConfiguration; + +} diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java similarity index 87% rename from rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java rename to rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java index d34755dc2c..f8e0fa2e29 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java @@ -16,18 +16,18 @@ package org.thingsboard.rule.engine.api; import org.thingsboard.server.common.data.plugin.ComponentScope; +import org.thingsboard.server.common.data.plugin.ComponentType; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * @author Andrew Shvayka - */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface FilterNode { +public @interface RuleNode { + + ComponentType type(); String name(); @@ -41,10 +41,9 @@ public @interface FilterNode { ComponentScope scope() default ComponentScope.TENANT; - String descriptor() default "EmptyNodeDescriptor.json"; + String defaultConfigResource() default "EmptyNodeConfig.json"; String[] relationTypes() default {"Success", "Failure"}; boolean customRelations() default false; - } diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java deleted file mode 100644 index 76b0dda01e..0000000000 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright © 2016-2018 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.api; - -import org.thingsboard.server.common.data.plugin.ComponentScope; -import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author Andrew Shvayka - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface TransformationNode { - - String name(); - - String nodeDescription(); - - String nodeDetails(); - - boolean inEnabled() default true; - - boolean outEnabled() default true; - - ComponentScope scope() default ComponentScope.TENANT; - - String descriptor() default "EmptyNodeDescriptor.json"; - - String[] relationTypes() default {"Success","Failure"}; - - boolean customRelations() default false; - -} diff --git a/rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json b/rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json new file mode 100644 index 0000000000..7a73a41bfd --- /dev/null +++ b/rule-engine/rule-engine-api/src/main/resources/EmptyNodeConfig.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java index 393496a41e..c85d4807e0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsFilterNode.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.TbNodeUtils; import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.js.NashornJsEngine; +import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import javax.script.Bindings; @@ -26,12 +27,14 @@ import javax.script.Bindings; import static org.thingsboard.rule.engine.DonAsynchron.withCallback; @Slf4j -@FilterNode(name = "script", relationTypes = {"True", "False", "Failure"}, +@RuleNode( + type = ComponentType.FILTER, + name = "script", relationTypes = {"True", "False", "Failure"}, nodeDescription = "Filter incoming messages using JS script", nodeDetails = "Evaluate incoming Message with configured JS condition. " + - "If 'True' - send Message via 'True' chain, otherwise 'False' chain is used." + - "Message payload can be accessed via 'msg' property. For example 'msg.temperature < 10;'" + - "Message metadata can be accessed via 'meta' property. For example 'meta.customerName === 'John';'") + "If True - send Message via True chain, otherwise False chain is used." + + "Message payload can be accessed via msg property. For example msg.temperature < 10;" + + "Message metadata can be accessed via meta property. For example meta.customerName === 'John';") public class TbJsFilterNode implements TbNode { private TbJsFilterNodeConfiguration config; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java index dff214567d..faf97b4e50 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbJsSwitchNode.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.TbNodeUtils; import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.js.NashornJsEngine; +import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import javax.script.Bindings; @@ -27,12 +28,14 @@ import java.util.Set; import static org.thingsboard.rule.engine.DonAsynchron.withCallback; @Slf4j -@FilterNode(name = "switch", customRelations = true, +@RuleNode( + type = ComponentType.FILTER, + name = "switch", customRelations = true, nodeDescription = "Route incoming Message to one or multiple output chains", nodeDetails = "Node executes configured JS script. Script should return array of next Chain names where Message should be routed. " + "If Array is empty - message not routed to next Node. " + - "Message payload can be accessed via 'msg' property. For example 'msg.temperature < 10;' " + - "Message metadata can be accessed via 'meta' property. For example 'meta.customerName === 'John';' ") + "Message payload can be accessed via msg property. For example msg.temperature < 10; " + + "Message metadata can be accessed via meta property. For example meta.customerName === 'John';") public class TbJsSwitchNode implements TbNode { private TbJsSwitchNodeConfiguration config; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java index c08c3e0bf5..7a6f9fdbee 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeFilterNode.java @@ -18,16 +18,19 @@ package org.thingsboard.rule.engine.filter; import lombok.extern.slf4j.Slf4j; import org.thingsboard.rule.engine.TbNodeUtils; import org.thingsboard.rule.engine.api.*; +import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; /** * Created by ashvayka on 19.01.18. */ @Slf4j -@FilterNode(name = "message type", +@RuleNode( + type = ComponentType.FILTER, + name = "message type", nodeDescription = "Filter incoming messages by Message Type", nodeDetails = "Evaluate incoming Message with configured JS condition. " + - "If incoming MessageType is expected - send Message via 'Success' chain, otherwise 'Failure' chain is used.") + "If incoming MessageType is expected - send Message via Success chain, otherwise Failure chain is used.") public class TbMsgTypeFilterNode implements TbNode { TbMsgTypeFilterNodeConfiguration config; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java index 216cf28015..6228206da8 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetAttributesNode.java @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.TbNodeUtils; import org.thingsboard.rule.engine.api.*; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import java.util.List; @@ -35,11 +36,12 @@ import static org.thingsboard.server.common.data.DataConstants.*; * Created by ashvayka on 19.01.18. */ @Slf4j -@EnrichmentNode(name = "originator attributes", - nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata", - nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message metadata " + - "with specific prefix: cs/shared/ss. To access those attributes in other nodes this template can be used " + - "'meta.cs.temperature' or 'meta.shared.limit' " + +@RuleNode(type = ComponentType.ENRICHMENT, + name = "originator attributes", + nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata", + nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message metadata " + + "with specific prefix: cs/shared/ss. To access those attributes in other nodes this template can be used " + + "meta.cs.temperature or meta.shared.limit " + "If Latest Telemetry enrichment configured, latest telemetry added into metadata without prefix.") public class TbGetAttributesNode implements TbNode { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java index c9cabaaabc..d85fb56de0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetCustomerAttributeNode.java @@ -16,17 +16,20 @@ package org.thingsboard.rule.engine.metadata; import com.google.common.util.concurrent.ListenableFuture; -import org.thingsboard.rule.engine.api.EnrichmentNode; +import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.plugin.ComponentType; -@EnrichmentNode(name="customer attributes", +@RuleNode( + type = ComponentType.ENRICHMENT, + name="customer attributes", nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata", nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + "To access those attributes in other nodes this template can be used " + - "'meta.temperature'. If Latest Telemetry enrichment configured, latest telemetry added into metadata") + "meta.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode { @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java index f85d019b04..26b756176c 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetRelatedAttributeNode.java @@ -17,22 +17,21 @@ package org.thingsboard.rule.engine.metadata; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.rule.engine.TbNodeUtils; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.rule.engine.api.TbNodeState; -import org.thingsboard.rule.engine.api.EnrichmentNode; +import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.plugin.ComponentType; -@EnrichmentNode(name="related attributes", +@RuleNode( + type = ComponentType.ENRICHMENT, + name="related attributes", nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata", nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " + "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + "To access those attributes in other nodes this template can be used " + - "'meta.temperature'. If Latest Telemetry enrichment configured, latest telemetry added into metadata") + "meta.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode { private TbGetRelatedAttrNodeConfiguration config; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java index 2603bc5cc1..7d9c50bfc6 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantAttributeNode.java @@ -17,18 +17,21 @@ package org.thingsboard.rule.engine.metadata; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.rule.engine.api.EnrichmentNode; +import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.plugin.ComponentType; @Slf4j -@EnrichmentNode(name="tenant attributes", +@RuleNode( + type = ComponentType.ENRICHMENT, + name="tenant attributes", nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata", nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + "To access those attributes in other nodes this template can be used " + - "'meta.temperature'. If Latest Telemetry enrichment configured, latest telemetry added into metadata") + "meta.temperature. If Latest Telemetry enrichment configured, latest telemetry added into metadata") public class TbGetTenantAttributeNode extends TbEntityGetAttrNode { @Override diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java index 8ab8e18abc..d237df83ce 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbChangeOriginatorNode.java @@ -27,12 +27,15 @@ import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import java.util.HashSet; @Slf4j -@TransformationNode(name="change originator", +@RuleNode( + type = ComponentType.TRANSFORMATION, + name="change originator", nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity", nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + "If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ") diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java index 3cd7cd1374..babdbc3085 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/transform/TbTransformMsgNode.java @@ -19,15 +19,18 @@ import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.rule.engine.TbNodeUtils; import org.thingsboard.rule.engine.api.*; import org.thingsboard.rule.engine.js.NashornJsEngine; +import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import javax.script.Bindings; -@TransformationNode(name = "script", +@RuleNode( + type = ComponentType.TRANSFORMATION, + name = "script", nodeDescription = "Change Message payload and Metadata using JavaScript", - nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside. " + - "'meta' - is a Message metadata. " + - "'msg' - is a Message payload. Any properties can be changed/removed/added in those objects.") + nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside.
" + + "meta - is a Message metadata.
" + + "msg - is a Message payload.
Any properties can be changed/removed/added in those objects.") public class TbTransformMsgNode extends TbAbstractTransformNode { private TbTransformMsgNodeConfiguration config; diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 2f8d152029..4dd961a11f 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -460,8 +460,19 @@ export default angular.module('thingsboard.types', []) ruleNodeTypeComponentTypes: ["FILTER", "ENRICHMENT", "TRANSFORMATION", "ACTION"], ruleChainNodeComponent: { type: 'RULE_CHAIN', - name: 'Rule chain', - clazz: 'tb.internal.RuleChain' + name: 'rule chain', + clazz: 'tb.internal.RuleChain', + configurationDescriptor: { + nodeDefinition: { + description: "Forwards incoming messages to specified Rule Chain", + details: "Forwards incoming messages to specified Rule Chain", + inEnabled: true, + outEnabled: false, + relationTypes: [], + customRelations: false, + defaultConfiguration: {} + } + } }, inputNodeComponent: { type: 'INPUT', diff --git a/ui/src/app/rulechain/rulechain.controller.js b/ui/src/app/rulechain/rulechain.controller.js index 76d0fec0c5..973618de6b 100644 --- a/ui/src/app/rulechain/rulechain.controller.js +++ b/ui/src/app/rulechain/rulechain.controller.js @@ -183,7 +183,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, '
' + '
' + '
' + node.component.name + '
' + - '
' + 'Some description of node' + '
' + + '
' + node.component.configurationDescriptor.nodeDefinition.description + '
' + + '
' + node.component.configurationDescriptor.nodeDefinition.details + '
' + '
' + '
' ); diff --git a/ui/src/app/rulechain/rulechain.scss b/ui/src/app/rulechain/rulechain.scss index 258e232ea4..26a5225a68 100644 --- a/ui/src/app/rulechain/rulechain.scss +++ b/ui/src/app/rulechain/rulechain.scss @@ -260,3 +260,32 @@ stroke-dashoffset: 500; } } + +.tb-rule-node-tooltip { + font-size: 14px; + width: 300px; + color: #333; + #tooltip-content { + .tb-node-title { + font-weight: 600; + } + .tb-node-description { + font-style: italic; + color: #555; + } + .tb-node-details { + padding-top: 10px; + padding-bottom: 10px; + } + code { + padding: 0px 3px 2px 3px; + margin: 1px; + color: #AD1625; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + border-radius: 2px; + font-size: 12px; + } + } +} \ No newline at end of file