Commit 7a687f373cd8352fe039af7d550997370c8486a5
1 parent
6106f4c0
Check Relations Node and Originator Fields
Showing
11 changed files
with
365 additions
and
4 deletions
... | ... | @@ -43,6 +43,7 @@ import org.thingsboard.server.dao.customer.CustomerService; |
43 | 43 | import org.thingsboard.server.dao.device.DeviceService; |
44 | 44 | import org.thingsboard.server.dao.relation.RelationService; |
45 | 45 | import org.thingsboard.server.dao.rule.RuleChainService; |
46 | +import org.thingsboard.server.dao.tenant.TenantService; | |
46 | 47 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
47 | 48 | import org.thingsboard.server.dao.user.UserService; |
48 | 49 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
... | ... | @@ -167,6 +168,11 @@ class DefaultTbContext implements TbContext { |
167 | 168 | } |
168 | 169 | |
169 | 170 | @Override |
171 | + public TenantService getTenantService() { | |
172 | + return mainCtx.getTenantService(); | |
173 | + } | |
174 | + | |
175 | + @Override | |
170 | 176 | public UserService getUserService() { |
171 | 177 | return mainCtx.getUserService(); |
172 | 178 | } | ... | ... |
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.server.common.data; | |
17 | + | |
18 | +import lombok.AllArgsConstructor; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.id.EntityId; | |
21 | + | |
22 | +/** | |
23 | + * Created by ashvayka on 01.06.18. | |
24 | + */ | |
25 | +@Data | |
26 | +@AllArgsConstructor | |
27 | +public class EntityFieldsData { | |
28 | + | |
29 | + public static final String DEFAULT = "default"; | |
30 | + | |
31 | + private final EntityId entityId; | |
32 | + private final String name; | |
33 | + private final String type; | |
34 | + | |
35 | + public EntityFieldsData(EntityId entityId, String name) { | |
36 | + this(entityId, name, DEFAULT); | |
37 | + } | |
38 | +} | ... | ... |
... | ... | @@ -28,6 +28,7 @@ import org.thingsboard.server.dao.customer.CustomerService; |
28 | 28 | import org.thingsboard.server.dao.device.DeviceService; |
29 | 29 | import org.thingsboard.server.dao.relation.RelationService; |
30 | 30 | import org.thingsboard.server.dao.rule.RuleChainService; |
31 | +import org.thingsboard.server.dao.tenant.TenantService; | |
31 | 32 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
32 | 33 | import org.thingsboard.server.dao.user.UserService; |
33 | 34 | |
... | ... | @@ -62,6 +63,8 @@ public interface TbContext { |
62 | 63 | |
63 | 64 | CustomerService getCustomerService(); |
64 | 65 | |
66 | + TenantService getTenantService(); | |
67 | + | |
65 | 68 | UserService getUserService(); |
66 | 69 | |
67 | 70 | AssetService getAssetService(); | ... | ... |
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.filter; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.thingsboard.rule.engine.api.RuleNode; | |
20 | +import org.thingsboard.rule.engine.api.TbContext; | |
21 | +import org.thingsboard.rule.engine.api.TbNode; | |
22 | +import org.thingsboard.rule.engine.api.TbNodeConfiguration; | |
23 | +import org.thingsboard.rule.engine.api.TbNodeException; | |
24 | +import org.thingsboard.rule.engine.api.util.TbNodeUtils; | |
25 | +import org.thingsboard.server.common.data.id.EntityId; | |
26 | +import org.thingsboard.server.common.data.id.EntityIdFactory; | |
27 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
28 | +import org.thingsboard.server.common.data.relation.EntitySearchDirection; | |
29 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | |
30 | +import org.thingsboard.server.common.msg.TbMsg; | |
31 | + | |
32 | +import javax.management.relation.RelationType; | |
33 | + | |
34 | +import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; | |
35 | +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; | |
36 | + | |
37 | +/** | |
38 | + * Created by ashvayka on 19.01.18. | |
39 | + */ | |
40 | +@Slf4j | |
41 | +@RuleNode( | |
42 | + type = ComponentType.FILTER, | |
43 | + name = "check relation", | |
44 | + configClazz = TbCheckRelationNodeConfiguration.class, | |
45 | + relationTypes = {"True", "False"}, | |
46 | + nodeDescription = "Checks the relation from the selected entity to originator of the message by type and direction", | |
47 | + nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.") | |
48 | +public class TbCheckRelationNode implements TbNode { | |
49 | + | |
50 | + private TbCheckRelationNodeConfiguration config; | |
51 | + | |
52 | + @Override | |
53 | + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | |
54 | + this.config = TbNodeUtils.convert(configuration, TbCheckRelationNodeConfiguration.class); | |
55 | + } | |
56 | + | |
57 | + @Override | |
58 | + public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { | |
59 | + EntityId from; | |
60 | + EntityId to; | |
61 | + if (EntitySearchDirection.FROM.name().equals(config.getDirection())) { | |
62 | + from = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId()); | |
63 | + to = msg.getOriginator(); | |
64 | + } else { | |
65 | + to = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId()); | |
66 | + from = msg.getOriginator(); | |
67 | + } | |
68 | + withCallback(ctx.getRelationService().checkRelation(from, to, config.getRelationType(), RelationTypeGroup.COMMON), | |
69 | + filterResult -> ctx.tellNext(msg, filterResult ? "True" : "False"), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public void destroy() { | |
74 | + | |
75 | + } | |
76 | +} | ... | ... |
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.filter; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.rule.engine.api.NodeConfiguration; | |
20 | +import org.thingsboard.server.common.data.relation.EntitySearchDirection; | |
21 | +import org.thingsboard.server.common.msg.session.SessionMsgType; | |
22 | + | |
23 | +import java.util.Arrays; | |
24 | +import java.util.List; | |
25 | + | |
26 | +/** | |
27 | + * Created by ashvayka on 19.01.18. | |
28 | + */ | |
29 | +@Data | |
30 | +public class TbCheckRelationNodeConfiguration implements NodeConfiguration<TbCheckRelationNodeConfiguration> { | |
31 | + | |
32 | + private String direction; | |
33 | + private String entityId; | |
34 | + private String entityType; | |
35 | + private String relationType; | |
36 | + | |
37 | + @Override | |
38 | + public TbCheckRelationNodeConfiguration defaultConfiguration() { | |
39 | + TbCheckRelationNodeConfiguration configuration = new TbCheckRelationNodeConfiguration(); | |
40 | + configuration.setDirection(EntitySearchDirection.FROM.name()); | |
41 | + configuration.setRelationType("Contains"); | |
42 | + return configuration; | |
43 | + } | |
44 | +} | ... | ... |
... | ... | @@ -51,7 +51,7 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC |
51 | 51 | public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { |
52 | 52 | try { |
53 | 53 | withCallback( |
54 | - findEntityAsync(ctx, msg.getOriginator()), | |
54 | + findEntityIdAsync(ctx, msg.getOriginator()), | |
55 | 55 | entityId -> safePutAttributes(ctx, msg, entityId), |
56 | 56 | t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); |
57 | 57 | } catch (Throwable th) { |
... | ... | @@ -112,5 +112,5 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC |
112 | 112 | |
113 | 113 | } |
114 | 114 | |
115 | - protected abstract ListenableFuture<T> findEntityAsync(TbContext ctx, EntityId originator); | |
115 | + protected abstract ListenableFuture<T> findEntityIdAsync(TbContext ctx, EntityId originator); | |
116 | 116 | } | ... | ... |
... | ... | @@ -48,7 +48,7 @@ public class TbGetAttributesNode extends TbAbstractGetAttributesNode<TbGetAttrib |
48 | 48 | } |
49 | 49 | |
50 | 50 | @Override |
51 | - protected ListenableFuture<EntityId> findEntityAsync(TbContext ctx, EntityId originator) { | |
51 | + protected ListenableFuture<EntityId> findEntityIdAsync(TbContext ctx, EntityId originator) { | |
52 | 52 | return Futures.immediateFuture(originator); |
53 | 53 | } |
54 | 54 | } | ... | ... |
... | ... | @@ -46,7 +46,7 @@ public class TbGetDeviceAttrNode extends TbAbstractGetAttributesNode<TbGetDevice |
46 | 46 | } |
47 | 47 | |
48 | 48 | @Override |
49 | - protected ListenableFuture<DeviceId> findEntityAsync(TbContext ctx, EntityId originator) { | |
49 | + protected ListenableFuture<DeviceId> findEntityIdAsync(TbContext ctx, EntityId originator) { | |
50 | 50 | return EntitiesRelatedDeviceIdAsyncLoader.findDeviceAsync(ctx, originator, config.getDeviceRelationsQuery()); |
51 | 51 | } |
52 | 52 | } | ... | ... |
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.metadata; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.rule.engine.api.NodeConfiguration; | |
20 | + | |
21 | +@Data | |
22 | +public class TbGetOriginatorFieldsConfiguration implements NodeConfiguration<TbGetOriginatorFieldsConfiguration> { | |
23 | + | |
24 | + private boolean fetchName; | |
25 | + private String nameMetadataKey; | |
26 | + private boolean fetchType; | |
27 | + private String typeMetadataKey; | |
28 | + | |
29 | + @Override | |
30 | + public TbGetOriginatorFieldsConfiguration defaultConfiguration() { | |
31 | + TbGetOriginatorFieldsConfiguration configuration = new TbGetOriginatorFieldsConfiguration(); | |
32 | + configuration.setFetchName(true); | |
33 | + configuration.setNameMetadataKey("entityName"); | |
34 | + configuration.setFetchType(true); | |
35 | + configuration.setTypeMetadataKey("entityType"); | |
36 | + return configuration; | |
37 | + } | |
38 | +} | ... | ... |
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.metadata; | |
17 | + | |
18 | +import com.google.common.util.concurrent.Futures; | |
19 | +import com.google.common.util.concurrent.ListenableFuture; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.thingsboard.rule.engine.api.RuleNode; | |
22 | +import org.thingsboard.rule.engine.api.TbContext; | |
23 | +import org.thingsboard.rule.engine.api.TbNode; | |
24 | +import org.thingsboard.rule.engine.api.TbNodeConfiguration; | |
25 | +import org.thingsboard.rule.engine.api.TbNodeException; | |
26 | +import org.thingsboard.rule.engine.api.util.TbNodeUtils; | |
27 | +import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader; | |
28 | +import org.thingsboard.server.common.data.id.EntityId; | |
29 | +import org.thingsboard.server.common.data.plugin.ComponentType; | |
30 | +import org.thingsboard.server.common.msg.TbMsg; | |
31 | + | |
32 | +import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; | |
33 | +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; | |
34 | + | |
35 | +/** | |
36 | + * Created by ashvayka on 19.01.18. | |
37 | + */ | |
38 | +@Slf4j | |
39 | +@RuleNode(type = ComponentType.ENRICHMENT, | |
40 | + name = "entity fields", | |
41 | + configClazz = TbGetOriginatorFieldsConfiguration.class, | |
42 | + nodeDescription = "Add Message Originator Name and Type into Message Metadata", | |
43 | + nodeDetails = "If originator is Asset, Device or Alarm, both name and type are added. In all other cases type will always be \"default\"") | |
44 | +public class TbGetOriginatorFieldsNode implements TbNode { | |
45 | + | |
46 | + private TbGetOriginatorFieldsConfiguration config; | |
47 | + | |
48 | + @Override | |
49 | + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { | |
50 | + config = TbNodeUtils.convert(configuration, TbGetOriginatorFieldsConfiguration.class); | |
51 | + } | |
52 | + | |
53 | + @Override | |
54 | + public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { | |
55 | + try { | |
56 | + withCallback(putEntityFields(ctx, msg.getOriginator(), msg), | |
57 | + i -> ctx.tellNext(msg, SUCCESS), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); | |
58 | + } catch (Throwable th) { | |
59 | + ctx.tellFailure(msg, th); | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + private ListenableFuture<Void> putEntityFields(TbContext ctx, EntityId entityId, TbMsg msg) { | |
64 | + if (!config.isFetchName() && !config.isFetchType()) { | |
65 | + return Futures.immediateFuture(null); | |
66 | + } else { | |
67 | + return Futures.transform(EntitiesFieldsAsyncLoader.findAsync(ctx, entityId), | |
68 | + data -> { | |
69 | + if (config.isFetchName()) { | |
70 | + msg.getMetaData().putValue(config.getNameMetadataKey(), data.getName()); | |
71 | + } | |
72 | + if (config.isFetchType()) { | |
73 | + msg.getMetaData().putValue(config.getTypeMetadataKey(), data.getType()); | |
74 | + } | |
75 | + return null; | |
76 | + } | |
77 | + ); | |
78 | + } | |
79 | + } | |
80 | + | |
81 | + @Override | |
82 | + public void destroy() { | |
83 | + | |
84 | + } | |
85 | +} | ... | ... |
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.util; | |
17 | + | |
18 | +import com.google.common.util.concurrent.Futures; | |
19 | +import com.google.common.util.concurrent.ListenableFuture; | |
20 | +import org.thingsboard.rule.engine.api.TbContext; | |
21 | +import org.thingsboard.rule.engine.api.TbNodeException; | |
22 | +import org.thingsboard.server.common.data.BaseData; | |
23 | +import org.thingsboard.server.common.data.EntityFieldsData; | |
24 | +import org.thingsboard.server.common.data.alarm.AlarmId; | |
25 | +import org.thingsboard.server.common.data.id.AssetId; | |
26 | +import org.thingsboard.server.common.data.id.CustomerId; | |
27 | +import org.thingsboard.server.common.data.id.DeviceId; | |
28 | +import org.thingsboard.server.common.data.id.EntityId; | |
29 | +import org.thingsboard.server.common.data.id.RuleChainId; | |
30 | +import org.thingsboard.server.common.data.id.TenantId; | |
31 | +import org.thingsboard.server.common.data.id.UserId; | |
32 | + | |
33 | +import java.util.function.Function; | |
34 | + | |
35 | +public class EntitiesFieldsAsyncLoader { | |
36 | + | |
37 | + public static ListenableFuture<EntityFieldsData> findAsync(TbContext ctx, EntityId original) { | |
38 | + switch (original.getEntityType()) { | |
39 | + case TENANT: | |
40 | + return getAsync(ctx.getTenantService().findTenantByIdAsync((TenantId) original), | |
41 | + t -> new EntityFieldsData(t.getId(), t.getName())); | |
42 | + case CUSTOMER: | |
43 | + return getAsync(ctx.getCustomerService().findCustomerByIdAsync((CustomerId) original), | |
44 | + t -> new EntityFieldsData(t.getId(), t.getName())); | |
45 | + case USER: | |
46 | + return getAsync(ctx.getUserService().findUserByIdAsync((UserId) original), | |
47 | + t -> new EntityFieldsData(t.getId(), t.getName())); | |
48 | + case ASSET: | |
49 | + return getAsync(ctx.getAssetService().findAssetByIdAsync((AssetId) original), | |
50 | + t -> new EntityFieldsData(t.getId(), t.getName(), t.getType())); | |
51 | + case DEVICE: | |
52 | + return getAsync(ctx.getDeviceService().findDeviceByIdAsync((DeviceId) original), | |
53 | + t -> new EntityFieldsData(t.getId(), t.getName(), t.getType())); | |
54 | + case ALARM: | |
55 | + return getAsync(ctx.getAlarmService().findAlarmByIdAsync((AlarmId) original), | |
56 | + t -> new EntityFieldsData(t.getId(), t.getName(), t.getType())); | |
57 | + case RULE_CHAIN: | |
58 | + return getAsync(ctx.getRuleChainService().findRuleChainByIdAsync((RuleChainId) original), | |
59 | + t -> new EntityFieldsData(t.getId(), t.getName())); | |
60 | + default: | |
61 | + return Futures.immediateFailedFuture(new TbNodeException("Unexpected original EntityType " + original)); | |
62 | + } | |
63 | + } | |
64 | + | |
65 | + private static <T extends BaseData> ListenableFuture<EntityFieldsData> getAsync( | |
66 | + ListenableFuture<T> future, Function<T, EntityFieldsData> converter) { | |
67 | + return Futures.transformAsync(future, in -> in != null ? | |
68 | + Futures.immediateFuture(converter.apply(in)) | |
69 | + : Futures.immediateFailedFuture(new RuntimeException("Entity not found!"))); | |
70 | + } | |
71 | +} | ... | ... |