Commit 7a687f373cd8352fe039af7d550997370c8486a5

Authored by Andrew Shvayka
1 parent 6106f4c0

Check Relations Node and Originator Fields

... ... @@ -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 +}
... ...