Showing
18 changed files
with
173 additions
and
197 deletions
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.server.service.component; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; |
19 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
20 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | 21 | import com.google.common.base.Charsets; |
20 | 22 | import com.google.common.io.Resources; |
21 | 23 | import lombok.extern.slf4j.Slf4j; |
... | ... | @@ -26,16 +28,14 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponen |
26 | 28 | import org.springframework.core.env.Environment; |
27 | 29 | import org.springframework.core.type.filter.AnnotationTypeFilter; |
28 | 30 | import org.springframework.stereotype.Service; |
29 | -import org.thingsboard.rule.engine.api.ActionNode; | |
30 | -import org.thingsboard.rule.engine.api.EnrichmentNode; | |
31 | -import org.thingsboard.rule.engine.api.FilterNode; | |
32 | -import org.thingsboard.rule.engine.api.TransformationNode; | |
31 | +import org.thingsboard.rule.engine.api.*; | |
33 | 32 | import org.thingsboard.server.common.data.plugin.ComponentDescriptor; |
34 | 33 | import org.thingsboard.server.common.data.plugin.ComponentType; |
35 | 34 | import org.thingsboard.server.dao.component.ComponentDescriptorService; |
36 | 35 | import org.thingsboard.server.extensions.api.component.*; |
37 | 36 | |
38 | 37 | import javax.annotation.PostConstruct; |
38 | +import java.io.IOException; | |
39 | 39 | import java.lang.annotation.Annotation; |
40 | 40 | import java.util.*; |
41 | 41 | import java.util.stream.Collectors; |
... | ... | @@ -70,6 +70,24 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
70 | 70 | } |
71 | 71 | } |
72 | 72 | |
73 | + private void registerRuleNodeComponents() { | |
74 | + Set<BeanDefinition> ruleNodeBeanDefinitions = getBeanDefinitions(RuleNode.class); | |
75 | + for (BeanDefinition def : ruleNodeBeanDefinitions) { | |
76 | + try { | |
77 | + String clazzName = def.getBeanClassName(); | |
78 | + Class<?> clazz = Class.forName(clazzName); | |
79 | + RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); | |
80 | + ComponentType type = ruleNodeAnnotation.type(); | |
81 | + ComponentDescriptor component = scanAndPersistComponent(def, type); | |
82 | + components.put(component.getClazz(), component); | |
83 | + componentsMap.computeIfAbsent(type, k -> new ArrayList<>()).add(component); | |
84 | + } catch (Exception e) { | |
85 | + log.error("Can't initialize component {}, due to {}", def.getBeanClassName(), e.getMessage(), e); | |
86 | + throw new RuntimeException(e); | |
87 | + } | |
88 | + } | |
89 | + } | |
90 | + | |
73 | 91 | private void registerComponents(ComponentType type, Class<? extends Annotation> annotation) { |
74 | 92 | List<ComponentDescriptor> components = persist(getBeanDefinitions(annotation), type); |
75 | 93 | componentsMap.put(type, components); |
... | ... | @@ -97,34 +115,25 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
97 | 115 | String descriptorResourceName; |
98 | 116 | switch (type) { |
99 | 117 | case ENRICHMENT: |
100 | - EnrichmentNode enrichmentAnnotation = clazz.getAnnotation(EnrichmentNode.class); | |
101 | - scannedComponent.setName(enrichmentAnnotation.name()); | |
102 | - scannedComponent.setScope(enrichmentAnnotation.scope()); | |
103 | - descriptorResourceName = enrichmentAnnotation.descriptor(); | |
104 | - break; | |
105 | 118 | case FILTER: |
106 | - FilterNode filterAnnotation = clazz.getAnnotation(FilterNode.class); | |
107 | - scannedComponent.setName(filterAnnotation.name()); | |
108 | - scannedComponent.setScope(filterAnnotation.scope()); | |
109 | - descriptorResourceName = filterAnnotation.descriptor(); | |
110 | - break; | |
111 | 119 | case TRANSFORMATION: |
112 | - TransformationNode trAnnotation = clazz.getAnnotation(TransformationNode.class); | |
113 | - scannedComponent.setName(trAnnotation.name()); | |
114 | - scannedComponent.setScope(trAnnotation.scope()); | |
115 | - descriptorResourceName = trAnnotation.descriptor(); | |
116 | - break; | |
117 | 120 | case ACTION: |
118 | - ActionNode actionAnnotation = clazz.getAnnotation(ActionNode.class); | |
119 | - scannedComponent.setName(actionAnnotation.name()); | |
120 | - scannedComponent.setScope(actionAnnotation.scope()); | |
121 | - descriptorResourceName = actionAnnotation.descriptor(); | |
121 | + RuleNode ruleNodeAnnotation = clazz.getAnnotation(RuleNode.class); | |
122 | + scannedComponent.setName(ruleNodeAnnotation.name()); | |
123 | + scannedComponent.setScope(ruleNodeAnnotation.scope()); | |
124 | + NodeDefinition nodeDefinition = prepareNodeDefinition(ruleNodeAnnotation); | |
125 | + ObjectNode configurationDescriptor = mapper.createObjectNode(); | |
126 | + JsonNode node = mapper.valueToTree(nodeDefinition); | |
127 | + configurationDescriptor.set("nodeDefinition", node); | |
128 | + scannedComponent.setConfigurationDescriptor(configurationDescriptor); | |
122 | 129 | break; |
123 | 130 | case OLD_ACTION: |
124 | 131 | Action oldActionAnnotation = clazz.getAnnotation(Action.class); |
125 | 132 | scannedComponent.setName(oldActionAnnotation.name()); |
126 | 133 | scannedComponent.setScope(oldActionAnnotation.scope()); |
127 | 134 | descriptorResourceName = oldActionAnnotation.descriptor(); |
135 | + scannedComponent.setConfigurationDescriptor(mapper.readTree( | |
136 | + Resources.toString(Resources.getResource(descriptorResourceName), Charsets.UTF_8))); | |
128 | 137 | break; |
129 | 138 | case PLUGIN: |
130 | 139 | Plugin pluginAnnotation = clazz.getAnnotation(Plugin.class); |
... | ... | @@ -143,12 +152,12 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
143 | 152 | } |
144 | 153 | } |
145 | 154 | scannedComponent.setActions(Arrays.stream(pluginAnnotation.actions()).map(Class::getName).collect(Collectors.joining(","))); |
155 | + scannedComponent.setConfigurationDescriptor(mapper.readTree( | |
156 | + Resources.toString(Resources.getResource(descriptorResourceName), Charsets.UTF_8))); | |
146 | 157 | break; |
147 | 158 | default: |
148 | 159 | throw new RuntimeException(type + " is not supported yet!"); |
149 | 160 | } |
150 | - scannedComponent.setConfigurationDescriptor(mapper.readTree( | |
151 | - Resources.toString(Resources.getResource(descriptorResourceName), Charsets.UTF_8))); | |
152 | 161 | scannedComponent.setClazz(clazzName); |
153 | 162 | log.info("Processing scanned component: {}", scannedComponent); |
154 | 163 | } catch (Exception e) { |
... | ... | @@ -171,6 +180,20 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
171 | 180 | return scannedComponent; |
172 | 181 | } |
173 | 182 | |
183 | + private NodeDefinition prepareNodeDefinition(RuleNode nodeAnnotation) throws IOException { | |
184 | + NodeDefinition nodeDefinition = new NodeDefinition(); | |
185 | + nodeDefinition.setDetails(nodeAnnotation.nodeDetails()); | |
186 | + nodeDefinition.setDescription(nodeAnnotation.nodeDescription()); | |
187 | + nodeDefinition.setInEnabled(nodeAnnotation.inEnabled()); | |
188 | + nodeDefinition.setOutEnabled(nodeAnnotation.outEnabled()); | |
189 | + nodeDefinition.setRelationTypes(nodeAnnotation.relationTypes()); | |
190 | + nodeDefinition.setCustomRelations(nodeAnnotation.customRelations()); | |
191 | + String defaultConfigResourceName = nodeAnnotation.defaultConfigResource(); | |
192 | + nodeDefinition.setDefaultConfiguration(mapper.readTree( | |
193 | + Resources.toString(Resources.getResource(defaultConfigResourceName), Charsets.UTF_8))); | |
194 | + return nodeDefinition; | |
195 | + } | |
196 | + | |
174 | 197 | private Set<BeanDefinition> getBeanDefinitions(Class<? extends Annotation> componentType) { |
175 | 198 | ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); |
176 | 199 | scanner.addIncludeFilter(new AnnotationTypeFilter(componentType)); |
... | ... | @@ -183,13 +206,8 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
183 | 206 | |
184 | 207 | @Override |
185 | 208 | public void discoverComponents() { |
186 | - registerComponents(ComponentType.ENRICHMENT, EnrichmentNode.class); | |
187 | - | |
188 | - registerComponents(ComponentType.FILTER, FilterNode.class); | |
189 | - | |
190 | - registerComponents(ComponentType.TRANSFORMATION, TransformationNode.class); | |
191 | 209 | |
192 | - registerComponents(ComponentType.ACTION, ActionNode.class); | |
210 | + registerRuleNodeComponents(); | |
193 | 211 | |
194 | 212 | registerComponents(ComponentType.OLD_ACTION, Action.class); |
195 | 213 | |
... | ... | @@ -200,15 +218,19 @@ public class AnnotationComponentDiscoveryService implements ComponentDiscoverySe |
200 | 218 | |
201 | 219 | @Override |
202 | 220 | public List<ComponentDescriptor> getComponents(ComponentType type) { |
203 | - return Collections.unmodifiableList(componentsMap.get(type)); | |
221 | + if (componentsMap.containsKey(type)) { | |
222 | + return Collections.unmodifiableList(componentsMap.get(type)); | |
223 | + } else { | |
224 | + return Collections.emptyList(); | |
225 | + } | |
204 | 226 | } |
205 | 227 | |
206 | 228 | @Override |
207 | 229 | public List<ComponentDescriptor> getComponents(Set<ComponentType> types) { |
208 | 230 | List<ComponentDescriptor> result = new ArrayList<>(); |
209 | - for (ComponentType type : types) { | |
231 | + types.stream().filter(type -> componentsMap.containsKey(type)).forEach(type -> { | |
210 | 232 | result.addAll(componentsMap.get(type)); |
211 | - } | |
233 | + }); | |
212 | 234 | return Collections.unmodifiableList(result); |
213 | 235 | } |
214 | 236 | ... | ... |
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/FilterNode.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.rule.engine.api; | |
17 | - | |
18 | -import org.thingsboard.server.common.data.plugin.ComponentScope; | |
19 | - | |
20 | -import java.lang.annotation.ElementType; | |
21 | -import java.lang.annotation.Retention; | |
22 | -import java.lang.annotation.RetentionPolicy; | |
23 | -import java.lang.annotation.Target; | |
24 | - | |
25 | -/** | |
26 | - * @author Andrew Shvayka | |
27 | - */ | |
28 | -@Retention(RetentionPolicy.RUNTIME) | |
29 | -@Target(ElementType.TYPE) | |
30 | -public @interface FilterNode { | |
31 | - | |
32 | - String name(); | |
33 | - | |
34 | - String nodeDescription(); | |
35 | - | |
36 | - String nodeDetails(); | |
37 | - | |
38 | - boolean inEnabled() default true; | |
39 | - | |
40 | - boolean outEnabled() default true; | |
41 | - | |
42 | - ComponentScope scope() default ComponentScope.TENANT; | |
43 | - | |
44 | - String descriptor() default "EmptyNodeDescriptor.json"; | |
45 | - | |
46 | - String[] relationTypes() default {"Success", "Failure"}; | |
47 | - | |
48 | - boolean customRelations() default false; | |
49 | - | |
50 | -} |
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/NodeDefinition.java
renamed from
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/ActionNode.java
... | ... | @@ -13,31 +13,21 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.rule.engine.api; | |
17 | - | |
18 | -import org.thingsboard.server.common.data.plugin.ComponentScope; | |
19 | -import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; | |
20 | - | |
21 | -import java.lang.annotation.ElementType; | |
22 | -import java.lang.annotation.Retention; | |
23 | -import java.lang.annotation.RetentionPolicy; | |
24 | -import java.lang.annotation.Target; | |
25 | - | |
26 | -/** | |
27 | - * @author Andrew Shvayka | |
28 | - */ | |
29 | -@Retention(RetentionPolicy.RUNTIME) | |
30 | -@Target(ElementType.TYPE) | |
31 | -public @interface ActionNode { | |
32 | 16 | |
33 | - String name(); | |
34 | - | |
35 | - ComponentScope scope() default ComponentScope.TENANT; | |
17 | +package org.thingsboard.rule.engine.api; | |
36 | 18 | |
37 | - String descriptor() default "EmptyNodeDescriptor.json"; | |
19 | +import com.fasterxml.jackson.databind.JsonNode; | |
20 | +import lombok.Data; | |
38 | 21 | |
39 | - String[] relationTypes() default {"Success","Failure"}; | |
22 | +@Data | |
23 | +public class NodeDefinition { | |
40 | 24 | |
41 | - boolean customRelations() default false; | |
25 | + private String details; | |
26 | + private String description; | |
27 | + private boolean inEnabled; | |
28 | + private boolean outEnabled; | |
29 | + String[] relationTypes; | |
30 | + boolean customRelations; | |
31 | + JsonNode defaultConfiguration; | |
42 | 32 | |
43 | 33 | } | ... | ... |
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleNode.java
renamed from
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/EnrichmentNode.java
... | ... | @@ -16,18 +16,18 @@ |
16 | 16 | package org.thingsboard.rule.engine.api; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.plugin.ComponentScope; |
19 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
19 | 20 | |
20 | 21 | import java.lang.annotation.ElementType; |
21 | 22 | import java.lang.annotation.Retention; |
22 | 23 | import java.lang.annotation.RetentionPolicy; |
23 | 24 | import java.lang.annotation.Target; |
24 | 25 | |
25 | -/** | |
26 | - * @author Andrew Shvayka | |
27 | - */ | |
28 | 26 | @Retention(RetentionPolicy.RUNTIME) |
29 | 27 | @Target(ElementType.TYPE) |
30 | -public @interface EnrichmentNode { | |
28 | +public @interface RuleNode { | |
29 | + | |
30 | + ComponentType type(); | |
31 | 31 | |
32 | 32 | String name(); |
33 | 33 | |
... | ... | @@ -41,7 +41,7 @@ public @interface EnrichmentNode { |
41 | 41 | |
42 | 42 | ComponentScope scope() default ComponentScope.TENANT; |
43 | 43 | |
44 | - String descriptor() default "EmptyNodeDescriptor.json"; | |
44 | + String defaultConfigResource() default "EmptyNodeConfig.json"; | |
45 | 45 | |
46 | 46 | String[] relationTypes() default {"Success", "Failure"}; |
47 | 47 | ... | ... |
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TransformationNode.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2018 The Thingsboard Authors | |
3 | - * | |
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | - * you may not use this file except in compliance with the License. | |
6 | - * You may obtain a copy of the License at | |
7 | - * | |
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | - * | |
10 | - * Unless required by applicable law or agreed to in writing, software | |
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | - * See the License for the specific language governing permissions and | |
14 | - * limitations under the License. | |
15 | - */ | |
16 | -package org.thingsboard.rule.engine.api; | |
17 | - | |
18 | -import org.thingsboard.server.common.data.plugin.ComponentScope; | |
19 | -import org.thingsboard.server.extensions.api.component.EmptyComponentConfiguration; | |
20 | - | |
21 | -import java.lang.annotation.ElementType; | |
22 | -import java.lang.annotation.Retention; | |
23 | -import java.lang.annotation.RetentionPolicy; | |
24 | -import java.lang.annotation.Target; | |
25 | - | |
26 | -/** | |
27 | - * @author Andrew Shvayka | |
28 | - */ | |
29 | -@Retention(RetentionPolicy.RUNTIME) | |
30 | -@Target(ElementType.TYPE) | |
31 | -public @interface TransformationNode { | |
32 | - | |
33 | - String name(); | |
34 | - | |
35 | - String nodeDescription(); | |
36 | - | |
37 | - String nodeDetails(); | |
38 | - | |
39 | - boolean inEnabled() default true; | |
40 | - | |
41 | - boolean outEnabled() default true; | |
42 | - | |
43 | - ComponentScope scope() default ComponentScope.TENANT; | |
44 | - | |
45 | - String descriptor() default "EmptyNodeDescriptor.json"; | |
46 | - | |
47 | - String[] relationTypes() default {"Success","Failure"}; | |
48 | - | |
49 | - boolean customRelations() default false; | |
50 | - | |
51 | -} |
... | ... | @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; |
19 | 19 | import org.thingsboard.rule.engine.TbNodeUtils; |
20 | 20 | import org.thingsboard.rule.engine.api.*; |
21 | 21 | import org.thingsboard.rule.engine.js.NashornJsEngine; |
22 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
22 | 23 | import org.thingsboard.server.common.msg.TbMsg; |
23 | 24 | |
24 | 25 | import javax.script.Bindings; |
... | ... | @@ -26,12 +27,14 @@ import javax.script.Bindings; |
26 | 27 | import static org.thingsboard.rule.engine.DonAsynchron.withCallback; |
27 | 28 | |
28 | 29 | @Slf4j |
29 | -@FilterNode(name = "script", relationTypes = {"True", "False", "Failure"}, | |
30 | +@RuleNode( | |
31 | + type = ComponentType.FILTER, | |
32 | + name = "script", relationTypes = {"True", "False", "Failure"}, | |
30 | 33 | nodeDescription = "Filter incoming messages using JS script", |
31 | 34 | nodeDetails = "Evaluate incoming Message with configured JS condition. " + |
32 | - "If 'True' - send Message via 'True' chain, otherwise 'False' chain is used." + | |
33 | - "Message payload can be accessed via 'msg' property. For example 'msg.temperature < 10;'" + | |
34 | - "Message metadata can be accessed via 'meta' property. For example 'meta.customerName === 'John';'") | |
35 | + "If <b>True</b> - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used." + | |
36 | + "Message payload can be accessed via <code>msg</code> property. For example <code>msg.temperature < 10;</code>" + | |
37 | + "Message metadata can be accessed via <code>meta</code> property. For example <code>meta.customerName === 'John';</code>") | |
35 | 38 | public class TbJsFilterNode implements TbNode { |
36 | 39 | |
37 | 40 | private TbJsFilterNodeConfiguration config; | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; |
19 | 19 | import org.thingsboard.rule.engine.TbNodeUtils; |
20 | 20 | import org.thingsboard.rule.engine.api.*; |
21 | 21 | import org.thingsboard.rule.engine.js.NashornJsEngine; |
22 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
22 | 23 | import org.thingsboard.server.common.msg.TbMsg; |
23 | 24 | |
24 | 25 | import javax.script.Bindings; |
... | ... | @@ -27,12 +28,14 @@ import java.util.Set; |
27 | 28 | import static org.thingsboard.rule.engine.DonAsynchron.withCallback; |
28 | 29 | |
29 | 30 | @Slf4j |
30 | -@FilterNode(name = "switch", customRelations = true, | |
31 | +@RuleNode( | |
32 | + type = ComponentType.FILTER, | |
33 | + name = "switch", customRelations = true, | |
31 | 34 | nodeDescription = "Route incoming Message to one or multiple output chains", |
32 | 35 | nodeDetails = "Node executes configured JS script. Script should return array of next Chain names where Message should be routed. " + |
33 | 36 | "If Array is empty - message not routed to next Node. " + |
34 | - "Message payload can be accessed via 'msg' property. For example 'msg.temperature < 10;' " + | |
35 | - "Message metadata can be accessed via 'meta' property. For example 'meta.customerName === 'John';' ") | |
37 | + "Message payload can be accessed via <code>msg</code> property. For example <code>msg.temperature < 10;</code> " + | |
38 | + "Message metadata can be accessed via <code>meta</code> property. For example <code>meta.customerName === 'John';</code>") | |
36 | 39 | public class TbJsSwitchNode implements TbNode { |
37 | 40 | |
38 | 41 | private TbJsSwitchNodeConfiguration config; | ... | ... |
... | ... | @@ -18,16 +18,19 @@ package org.thingsboard.rule.engine.filter; |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | 19 | import org.thingsboard.rule.engine.TbNodeUtils; |
20 | 20 | import org.thingsboard.rule.engine.api.*; |
21 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
21 | 22 | import org.thingsboard.server.common.msg.TbMsg; |
22 | 23 | |
23 | 24 | /** |
24 | 25 | * Created by ashvayka on 19.01.18. |
25 | 26 | */ |
26 | 27 | @Slf4j |
27 | -@FilterNode(name = "message type", | |
28 | +@RuleNode( | |
29 | + type = ComponentType.FILTER, | |
30 | + name = "message type", | |
28 | 31 | nodeDescription = "Filter incoming messages by Message Type", |
29 | 32 | nodeDetails = "Evaluate incoming Message with configured JS condition. " + |
30 | - "If incoming MessageType is expected - send Message via 'Success' chain, otherwise 'Failure' chain is used.") | |
33 | + "If incoming MessageType is expected - send Message via <b>Success</b> chain, otherwise <b>Failure</b> chain is used.") | |
31 | 34 | public class TbMsgTypeFilterNode implements TbNode { |
32 | 35 | |
33 | 36 | TbMsgTypeFilterNodeConfiguration config; | ... | ... |
... | ... | @@ -24,6 +24,7 @@ import org.thingsboard.rule.engine.TbNodeUtils; |
24 | 24 | import org.thingsboard.rule.engine.api.*; |
25 | 25 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
26 | 26 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
27 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
27 | 28 | import org.thingsboard.server.common.msg.TbMsg; |
28 | 29 | |
29 | 30 | import java.util.List; |
... | ... | @@ -35,11 +36,12 @@ import static org.thingsboard.server.common.data.DataConstants.*; |
35 | 36 | * Created by ashvayka on 19.01.18. |
36 | 37 | */ |
37 | 38 | @Slf4j |
38 | -@EnrichmentNode(name = "originator attributes", | |
39 | - nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata", | |
40 | - nodeDetails = "If Attributes enrichment configured, CLIENT/SHARED/SERVER attributes are added into Message metadata " + | |
41 | - "with specific prefix: cs/shared/ss. To access those attributes in other nodes this template can be used " + | |
42 | - "'meta.cs.temperature' or 'meta.shared.limit' " + | |
39 | +@RuleNode(type = ComponentType.ENRICHMENT, | |
40 | + name = "originator attributes", | |
41 | + nodeDescription = "Add Message Originator Attributes or Latest Telemetry into Message Metadata", | |
42 | + nodeDetails = "If Attributes enrichment configured, <b>CLIENT/SHARED/SERVER</b> attributes are added into Message metadata " + | |
43 | + "with specific prefix: <i>cs/shared/ss</i>. To access those attributes in other nodes this template can be used " + | |
44 | + "<code>meta.cs.temperature</code> or <code>meta.shared.limit</code> " + | |
43 | 45 | "If Latest Telemetry enrichment configured, latest telemetry added into metadata without prefix.") |
44 | 46 | public class TbGetAttributesNode implements TbNode { |
45 | 47 | ... | ... |
... | ... | @@ -16,17 +16,20 @@ |
16 | 16 | package org.thingsboard.rule.engine.metadata; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | -import org.thingsboard.rule.engine.api.EnrichmentNode; | |
19 | +import org.thingsboard.rule.engine.api.RuleNode; | |
20 | 20 | import org.thingsboard.rule.engine.api.TbContext; |
21 | 21 | import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader; |
22 | 22 | import org.thingsboard.server.common.data.id.CustomerId; |
23 | 23 | import org.thingsboard.server.common.data.id.EntityId; |
24 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
24 | 25 | |
25 | -@EnrichmentNode(name="customer attributes", | |
26 | +@RuleNode( | |
27 | + type = ComponentType.ENRICHMENT, | |
28 | + name="customer attributes", | |
26 | 29 | nodeDescription = "Add Originators Customer Attributes or Latest Telemetry into Message Metadata", |
27 | 30 | nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + |
28 | 31 | "To access those attributes in other nodes this template can be used " + |
29 | - "'meta.temperature'. If Latest Telemetry enrichment configured, latest telemetry added into metadata") | |
32 | + "<code>meta.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata") | |
30 | 33 | public class TbGetCustomerAttributeNode extends TbEntityGetAttrNode<CustomerId> { |
31 | 34 | |
32 | 35 | @Override | ... | ... |
... | ... | @@ -17,22 +17,21 @@ package org.thingsboard.rule.engine.metadata; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.rule.engine.TbNodeUtils; |
20 | -import org.thingsboard.rule.engine.api.TbContext; | |
21 | -import org.thingsboard.rule.engine.api.TbNodeConfiguration; | |
22 | -import org.thingsboard.rule.engine.api.TbNodeException; | |
23 | -import org.thingsboard.rule.engine.api.TbNodeState; | |
24 | -import org.thingsboard.rule.engine.api.EnrichmentNode; | |
20 | +import org.thingsboard.rule.engine.api.*; | |
25 | 21 | import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader; |
26 | 22 | |
27 | 23 | import org.thingsboard.server.common.data.id.EntityId; |
24 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
28 | 25 | |
29 | -@EnrichmentNode(name="related attributes", | |
26 | +@RuleNode( | |
27 | + type = ComponentType.ENRICHMENT, | |
28 | + name="related attributes", | |
30 | 29 | nodeDescription = "Add Originators Related Entity Attributes or Latest Telemetry into Message Metadata", |
31 | 30 | nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + |
32 | 31 | "If multiple Related Entities are found, only first Entity is used for attributes enrichment, other entities are discarded. " + |
33 | 32 | "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + |
34 | 33 | "To access those attributes in other nodes this template can be used " + |
35 | - "'meta.temperature'. If Latest Telemetry enrichment configured, latest telemetry added into metadata") | |
34 | + "<code>meta.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata") | |
36 | 35 | public class TbGetRelatedAttributeNode extends TbEntityGetAttrNode<EntityId> { |
37 | 36 | |
38 | 37 | private TbGetRelatedAttrNodeConfiguration config; | ... | ... |
... | ... | @@ -17,18 +17,21 @@ package org.thingsboard.rule.engine.metadata; |
17 | 17 | |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | -import org.thingsboard.rule.engine.api.EnrichmentNode; | |
20 | +import org.thingsboard.rule.engine.api.RuleNode; | |
21 | 21 | import org.thingsboard.rule.engine.api.TbContext; |
22 | 22 | import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader; |
23 | 23 | import org.thingsboard.server.common.data.id.EntityId; |
24 | 24 | import org.thingsboard.server.common.data.id.TenantId; |
25 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
25 | 26 | |
26 | 27 | @Slf4j |
27 | -@EnrichmentNode(name="tenant attributes", | |
28 | +@RuleNode( | |
29 | + type = ComponentType.ENRICHMENT, | |
30 | + name="tenant attributes", | |
28 | 31 | nodeDescription = "Add Originators Tenant Attributes or Latest Telemetry into Message Metadata", |
29 | 32 | nodeDetails = "If Attributes enrichment configured, server scope attributes are added into Message metadata. " + |
30 | 33 | "To access those attributes in other nodes this template can be used " + |
31 | - "'meta.temperature'. If Latest Telemetry enrichment configured, latest telemetry added into metadata") | |
34 | + "<code>meta.temperature</code>. If Latest Telemetry enrichment configured, latest telemetry added into metadata") | |
32 | 35 | public class TbGetTenantAttributeNode extends TbEntityGetAttrNode<TenantId> { |
33 | 36 | |
34 | 37 | @Override | ... | ... |
... | ... | @@ -27,12 +27,15 @@ import org.thingsboard.rule.engine.util.EntitiesCustomerIdAsyncLoader; |
27 | 27 | import org.thingsboard.rule.engine.util.EntitiesRelatedEntityIdAsyncLoader; |
28 | 28 | import org.thingsboard.rule.engine.util.EntitiesTenantIdAsyncLoader; |
29 | 29 | import org.thingsboard.server.common.data.id.EntityId; |
30 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
30 | 31 | import org.thingsboard.server.common.msg.TbMsg; |
31 | 32 | |
32 | 33 | import java.util.HashSet; |
33 | 34 | |
34 | 35 | @Slf4j |
35 | -@TransformationNode(name="change originator", | |
36 | +@RuleNode( | |
37 | + type = ComponentType.TRANSFORMATION, | |
38 | + name="change originator", | |
36 | 39 | nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity", |
37 | 40 | nodeDetails = "Related Entity found using configured relation direction and Relation Type. " + |
38 | 41 | "If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ") | ... | ... |
... | ... | @@ -19,15 +19,18 @@ import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.rule.engine.TbNodeUtils; |
20 | 20 | import org.thingsboard.rule.engine.api.*; |
21 | 21 | import org.thingsboard.rule.engine.js.NashornJsEngine; |
22 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
22 | 23 | import org.thingsboard.server.common.msg.TbMsg; |
23 | 24 | |
24 | 25 | import javax.script.Bindings; |
25 | 26 | |
26 | -@TransformationNode(name = "script", | |
27 | +@RuleNode( | |
28 | + type = ComponentType.TRANSFORMATION, | |
29 | + name = "script", | |
27 | 30 | nodeDescription = "Change Message payload and Metadata using JavaScript", |
28 | - nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside. " + | |
29 | - "'meta' - is a Message metadata. " + | |
30 | - "'msg' - is a Message payload. Any properties can be changed/removed/added in those objects.") | |
31 | + nodeDetails = "JavaScript function recieve 2 input parameters that can be changed inside.<br/> " + | |
32 | + "<code>meta</code> - is a Message metadata.<br/>" + | |
33 | + "<code>msg</code> - is a Message payload.<br/>Any properties can be changed/removed/added in those objects.") | |
31 | 34 | public class TbTransformMsgNode extends TbAbstractTransformNode { |
32 | 35 | |
33 | 36 | private TbTransformMsgNodeConfiguration config; | ... | ... |
... | ... | @@ -460,8 +460,19 @@ export default angular.module('thingsboard.types', []) |
460 | 460 | ruleNodeTypeComponentTypes: ["FILTER", "ENRICHMENT", "TRANSFORMATION", "ACTION"], |
461 | 461 | ruleChainNodeComponent: { |
462 | 462 | type: 'RULE_CHAIN', |
463 | - name: 'Rule chain', | |
464 | - clazz: 'tb.internal.RuleChain' | |
463 | + name: 'rule chain', | |
464 | + clazz: 'tb.internal.RuleChain', | |
465 | + configurationDescriptor: { | |
466 | + nodeDefinition: { | |
467 | + description: "Forwards incoming messages to specified Rule Chain", | |
468 | + details: "Forwards incoming messages to specified Rule Chain", | |
469 | + inEnabled: true, | |
470 | + outEnabled: false, | |
471 | + relationTypes: [], | |
472 | + customRelations: false, | |
473 | + defaultConfiguration: {} | |
474 | + } | |
475 | + } | |
465 | 476 | }, |
466 | 477 | inputNodeComponent: { |
467 | 478 | type: 'INPUT', | ... | ... |
... | ... | @@ -183,7 +183,8 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, |
183 | 183 | '<div class="tb-rule-node-tooltip">' + |
184 | 184 | '<div id="tooltip-content" layout="column">' + |
185 | 185 | '<div class="tb-node-title">' + node.component.name + '</div>' + |
186 | - '<div class="tb-node-description">' + 'Some description of node' + '</div>' + | |
186 | + '<div class="tb-node-description">' + node.component.configurationDescriptor.nodeDefinition.description + '</div>' + | |
187 | + '<div class="tb-node-details">' + node.component.configurationDescriptor.nodeDefinition.details + '</div>' + | |
187 | 188 | '</div>' + |
188 | 189 | '</div>' |
189 | 190 | ); | ... | ... |
... | ... | @@ -260,3 +260,32 @@ |
260 | 260 | stroke-dashoffset: 500; |
261 | 261 | } |
262 | 262 | } |
263 | + | |
264 | +.tb-rule-node-tooltip { | |
265 | + font-size: 14px; | |
266 | + width: 300px; | |
267 | + color: #333; | |
268 | + #tooltip-content { | |
269 | + .tb-node-title { | |
270 | + font-weight: 600; | |
271 | + } | |
272 | + .tb-node-description { | |
273 | + font-style: italic; | |
274 | + color: #555; | |
275 | + } | |
276 | + .tb-node-details { | |
277 | + padding-top: 10px; | |
278 | + padding-bottom: 10px; | |
279 | + } | |
280 | + code { | |
281 | + padding: 0px 3px 2px 3px; | |
282 | + margin: 1px; | |
283 | + color: #AD1625; | |
284 | + white-space: nowrap; | |
285 | + background-color: #f7f7f9; | |
286 | + border: 1px solid #e1e1e8; | |
287 | + border-radius: 2px; | |
288 | + font-size: 12px; | |
289 | + } | |
290 | + } | |
291 | +} | |
\ No newline at end of file | ... | ... |