Browse Source

Merge branch 'master' of github.com:thingsboard/thingsboard

pull/1635/head
nordmif 8 years ago
parent
commit
91ec610921
  1. 51
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java
  2. 3
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java
  3. 45
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java
  4. 57
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java
  5. 2
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNodeConfiguration.java
  6. 43
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java
  7. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java
  8. 8
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

51
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractRelationActionNode.java

@ -39,7 +39,9 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
@ -47,6 +49,7 @@ import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.entityview.EntityViewService;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -58,10 +61,8 @@ import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationActionNodeConfiguration> implements TbNode { public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationActionNodeConfiguration> implements TbNode {
protected C config; protected C config;
protected EntityId fromId;
protected EntityId toId;
private LoadingCache<Entitykey, EntityContainer> entityIdCache; private LoadingCache<EntityKey, EntityContainer> entityIdCache;
@Override @Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
@ -84,7 +85,7 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
public void destroy() { public void destroy() {
} }
private ListenableFuture<Boolean> processEntityRelationAction(TbContext ctx, TbMsg msg) { protected ListenableFuture<Boolean> processEntityRelationAction(TbContext ctx, TbMsg msg) {
return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer)); return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer));
} }
@ -96,40 +97,58 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
protected ListenableFuture<EntityContainer> getEntity(TbContext ctx, TbMsg msg) { protected ListenableFuture<EntityContainer> getEntity(TbContext ctx, TbMsg msg) {
String entityName = TbNodeUtils.processPattern(this.config.getEntityNamePattern(), msg.getMetaData()); String entityName = TbNodeUtils.processPattern(this.config.getEntityNamePattern(), msg.getMetaData());
String type = null; String type;
if (this.config.getEntityTypePattern() != null) { if (this.config.getEntityTypePattern() != null) {
type = TbNodeUtils.processPattern(this.config.getEntityTypePattern(), msg.getMetaData()); type = TbNodeUtils.processPattern(this.config.getEntityTypePattern(), msg.getMetaData());
} else {
type = null;
} }
EntityType entityType = EntityType.valueOf(this.config.getEntityType()); EntityType entityType = EntityType.valueOf(this.config.getEntityType());
Entitykey key = new Entitykey(entityName, type, entityType); EntityKey key = new EntityKey(entityName, type, entityType);
return ctx.getDbCallbackExecutor().executeAsync(() -> { return ctx.getDbCallbackExecutor().executeAsync(() -> {
EntityContainer entityContainer = entityIdCache.get(key); EntityContainer entityContainer = entityIdCache.get(key);
if (entityContainer.getEntityId() == null) { if (entityContainer.getEntityId() == null) {
throw new RuntimeException("No entity found with type '" + key.getEntityType() + " ' and name '" + key.getEntityName() + "'."); throw new RuntimeException("No entity found with type '" + key.getEntityType() + "' and name '" + key.getEntityName() + "'.");
} }
return entityContainer; return entityContainer;
}); });
} }
protected void processSearchDirection(TbMsg msg, EntityContainer entityContainer) { protected SearchDirectionIds processSingleSearchDirection(TbMsg msg, EntityContainer entityContainer) {
SearchDirectionIds searchDirectionIds = new SearchDirectionIds();
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) { if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
fromId = EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()); searchDirectionIds.setFromId(EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()));
toId = msg.getOriginator(); searchDirectionIds.setToId(msg.getOriginator());
} else { } else {
toId = EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()); searchDirectionIds.setToId(EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()));
fromId = msg.getOriginator(); searchDirectionIds.setFromId(msg.getOriginator());
}
return searchDirectionIds;
}
protected ListenableFuture<List<EntityRelation>> processListSearchDirection(TbContext ctx, TbMsg msg) {
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
return ctx.getRelationService().findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON);
} else {
return ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON);
} }
} }
@Data @Data
@AllArgsConstructor @AllArgsConstructor
private static class Entitykey { private static class EntityKey {
private String entityName; private String entityName;
private String type; private String type;
private EntityType entityType; private EntityType entityType;
} }
private static class EntityCacheLoader extends CacheLoader<Entitykey, EntityContainer> { @Data
protected static class SearchDirectionIds {
private EntityId fromId;
private EntityId toId;
}
private static class EntityCacheLoader extends CacheLoader<EntityKey, EntityContainer> {
private final TbContext ctx; private final TbContext ctx;
private final boolean createIfNotExists; private final boolean createIfNotExists;
@ -140,11 +159,11 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
} }
@Override @Override
public EntityContainer load(Entitykey key) { public EntityContainer load(EntityKey key) {
return loadEntity(key); return loadEntity(key);
} }
private EntityContainer loadEntity(Entitykey entitykey) { private EntityContainer loadEntity(EntityKey entitykey) {
EntityType type = entitykey.getEntityType(); EntityType type = entitykey.getEntityType();
EntityContainer targetEntity = new EntityContainer(); EntityContainer targetEntity = new EntityContainer();
targetEntity.setEntityType(type); targetEntity.setEntityType(type);

3
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbClearAlarmNode.java

@ -54,7 +54,8 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig
@Override @Override
protected ListenableFuture<AlarmResult> processAlarm(TbContext ctx, TbMsg msg) { protected ListenableFuture<AlarmResult> processAlarm(TbContext ctx, TbMsg msg) {
ListenableFuture<Alarm> latest = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), msg.getOriginator(), config.getAlarmType()); String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg.getMetaData());
ListenableFuture<Alarm> latest = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), msg.getOriginator(), alarmType);
return Futures.transformAsync(latest, a -> { return Futures.transformAsync(latest, a -> {
if (a != null && !a.getStatus().isCleared()) { if (a != null && !a.getStatus().isCleared()) {
return clearAlarm(ctx, msg, a); return clearAlarm(ctx, msg, a);

45
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbCreateRelationNode.java

@ -65,92 +65,91 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
} }
private ListenableFuture<Boolean> createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer) { private ListenableFuture<Boolean> createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
processSearchDirection(msg, entityContainer); SearchDirectionIds sdId = processSingleSearchDirection(msg, entityContainer);
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON), return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON),
result -> { result -> {
if (!result) { if (!result) {
return processCreateRelation(ctx, entityContainer); return processCreateRelation(ctx, entityContainer, sdId);
} }
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
}); });
} }
private ListenableFuture<Boolean> processCreateRelation(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processCreateRelation(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
switch (entityContainer.getEntityType()) { switch (entityContainer.getEntityType()) {
case ASSET: case ASSET:
return processAsset(ctx, entityContainer); return processAsset(ctx, entityContainer, sdId);
case DEVICE: case DEVICE:
return processDevice(ctx, entityContainer); return processDevice(ctx, entityContainer, sdId);
case CUSTOMER: case CUSTOMER:
return processCustomer(ctx, entityContainer); return processCustomer(ctx, entityContainer, sdId);
case DASHBOARD: case DASHBOARD:
return processDashboard(ctx, entityContainer); return processDashboard(ctx, entityContainer, sdId);
case ENTITY_VIEW: case ENTITY_VIEW:
return processView(ctx, entityContainer); return processView(ctx, entityContainer, sdId);
case TENANT: case TENANT:
return processTenant(ctx, entityContainer); return processTenant(ctx, entityContainer, sdId);
} }
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
private ListenableFuture<Boolean> processView(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processView(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(entityContainer.getEntityId().getId())), entityView -> { return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(entityContainer.getEntityId().getId())), entityView -> {
if (entityView != null) { if (entityView != null) {
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON));
} else { } else {
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
}); });
} }
private ListenableFuture<Boolean> processDevice(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processDevice(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(entityContainer.getEntityId().getId())), device -> { return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(entityContainer.getEntityId().getId())), device -> {
if (device != null) { if (device != null) {
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON));
} else { } else {
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
}); });
} }
private ListenableFuture<Boolean> processAsset(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processAsset(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(entityContainer.getEntityId().getId())), asset -> { return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(entityContainer.getEntityId().getId())), asset -> {
if (asset != null) { if (asset != null) {
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON));
} else { } else {
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
}); });
} }
private ListenableFuture<Boolean> processCustomer(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processCustomer(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
return Futures.transformAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), new CustomerId(entityContainer.getEntityId().getId())), customer -> { return Futures.transformAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), new CustomerId(entityContainer.getEntityId().getId())), customer -> {
if (customer != null) { if (customer != null) {
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON));
} else { } else {
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
}); });
} }
private ListenableFuture<Boolean> processDashboard(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processDashboard(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
return Futures.transformAsync(ctx.getDashboardService().findDashboardByIdAsync(ctx.getTenantId(), new DashboardId(entityContainer.getEntityId().getId())), dashboard -> { return Futures.transformAsync(ctx.getDashboardService().findDashboardByIdAsync(ctx.getTenantId(), new DashboardId(entityContainer.getEntityId().getId())), dashboard -> {
if (dashboard != null) { if (dashboard != null) {
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON));
} else { } else {
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
}); });
} }
private ListenableFuture<Boolean> processTenant(TbContext ctx, EntityContainer entityContainer) { private ListenableFuture<Boolean> processTenant(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), new TenantId(entityContainer.getEntityId().getId())), tenant -> { return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), new TenantId(entityContainer.getEntityId().getId())), tenant -> {
if (tenant != null) { if (tenant != null) {
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON));
} else { } else {
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
} }
}); });
} }
} }

57
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNode.java

@ -25,18 +25,24 @@ import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.rule.engine.util.EntityContainer; import org.thingsboard.rule.engine.util.EntityContainer;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import java.util.ArrayList;
import java.util.List;
@Slf4j @Slf4j
@RuleNode( @RuleNode(
type = ComponentType.ACTION, type = ComponentType.ACTION,
name = "delete relation", name = "delete relation",
configClazz = TbDeleteRelationNodeConfiguration.class, configClazz = TbDeleteRelationNodeConfiguration.class,
nodeDescription = "Finds target Entity by entity name pattern and then delete a relation to Originator Entity by type and direction.", nodeDescription = "Finds target Entity by entity name pattern and then delete a relation to Originator Entity by type and direction" +
nodeDetails = "If the relation successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", " if 'Delete single entity' is set to true, otherwise rule node will delete all relations to the originator of the message by type and direction.",
nodeDetails = "If the relation(s) successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbActionNodeDeleteRelationConfig", configDirective ="tbActionNodeDeleteRelationConfig",
icon = "remove_circle" icon = "remove_circle"
) )
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> { public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {
@ -51,24 +57,55 @@ public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteR
return false; return false;
} }
@Override
protected ListenableFuture<Boolean> processEntityRelationAction(TbContext ctx, TbMsg msg) {
if(config.isDeleteForSingleEntity()){
return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer));
} else {
return processList(ctx, msg);
}
}
@Override @Override
protected ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer) { protected ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
return deleteIfExist(ctx, msg, entityContainer); return processSingle(ctx, msg, entityContainer);
} }
private ListenableFuture<Boolean> deleteIfExist(TbContext ctx, TbMsg msg, EntityContainer entityContainer) { private ListenableFuture<Boolean> processList(TbContext ctx, TbMsg msg) {
processSearchDirection(msg, entityContainer); return Futures.transformAsync(processListSearchDirection(ctx, msg), entityRelations -> {
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON), if(entityRelations.isEmpty()){
return Futures.immediateFuture(true);
} else {
List<ListenableFuture<Boolean>> listenableFutureList = new ArrayList<>();
for (EntityRelation entityRelation: entityRelations) {
listenableFutureList.add(ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), entityRelation));
}
return Futures.transformAsync(Futures.allAsList(listenableFutureList), booleans -> {
for (Boolean bool : booleans) {
if (!bool) {
return Futures.immediateFuture(false);
}
}
return Futures.immediateFuture(true);
});
}
});
}
private ListenableFuture<Boolean> processSingle(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
SearchDirectionIds sdId = processSingleSearchDirection(msg, entityContainer);
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON),
result -> { result -> {
if (result) { if (result) {
return processDeleteRelation(ctx); return processSingleDeleteRelation(ctx, sdId);
} }
return Futures.immediateFuture(true); return Futures.immediateFuture(true);
}); });
} }
private ListenableFuture<Boolean> processDeleteRelation(TbContext ctx) { private ListenableFuture<Boolean> processSingleDeleteRelation(TbContext ctx, SearchDirectionIds sdId) {
return ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON); return ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), config.getRelationType(), RelationTypeGroup.COMMON);
} }
} }

2
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbDeleteRelationNodeConfiguration.java

@ -22,10 +22,12 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
@Data @Data
public class TbDeleteRelationNodeConfiguration extends TbAbstractRelationActionNodeConfiguration implements NodeConfiguration<TbDeleteRelationNodeConfiguration> { public class TbDeleteRelationNodeConfiguration extends TbAbstractRelationActionNodeConfiguration implements NodeConfiguration<TbDeleteRelationNodeConfiguration> {
private boolean deleteForSingleEntity;
@Override @Override
public TbDeleteRelationNodeConfiguration defaultConfiguration() { public TbDeleteRelationNodeConfiguration defaultConfiguration() {
TbDeleteRelationNodeConfiguration configuration = new TbDeleteRelationNodeConfiguration(); TbDeleteRelationNodeConfiguration configuration = new TbDeleteRelationNodeConfiguration();
configuration.setDeleteForSingleEntity(true);
configuration.setDirection(EntitySearchDirection.FROM.name()); configuration.setDirection(EntitySearchDirection.FROM.name());
configuration.setRelationType("Contains"); configuration.setRelationType("Contains");
configuration.setEntityNamePattern(""); configuration.setEntityNamePattern("");

43
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNode.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.rule.engine.filter; package org.thingsboard.rule.engine.filter;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.RuleNode; import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.api.TbContext;
@ -25,13 +27,13 @@ import org.thingsboard.rule.engine.api.util.TbNodeUtils;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import javax.management.relation.RelationType; import java.util.List;
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS;
import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
/** /**
@ -43,8 +45,10 @@ import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
name = "check relation", name = "check relation",
configClazz = TbCheckRelationNodeConfiguration.class, configClazz = TbCheckRelationNodeConfiguration.class,
relationTypes = {"True", "False"}, relationTypes = {"True", "False"},
nodeDescription = "Checks the relation from the selected entity to originator of the message by type and direction", nodeDescription = "Checks the relation from the selected entity to the originator of the message by type and direction" +
nodeDetails = "If relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.", " if 'Check for single entity' is set to true, otherwise rule node will check if exist" +
" any relation to the originator of the message by type and direction.",
nodeDetails = "If at least one relation exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"}, uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbFilterNodeCheckRelationConfig") configDirective = "tbFilterNodeCheckRelationConfig")
public class TbCheckRelationNode implements TbNode { public class TbCheckRelationNode implements TbNode {
@ -58,6 +62,16 @@ public class TbCheckRelationNode implements TbNode {
@Override @Override
public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException { public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
ListenableFuture<Boolean> checkRelationFuture;
if (config.isCheckForSingleEntity()) {
checkRelationFuture = processSingle(ctx, msg);
} else {
checkRelationFuture = processList(ctx, msg);
}
withCallback(checkRelationFuture, filterResult -> ctx.tellNext(msg, filterResult ? "True" : "False"), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
}
private ListenableFuture<Boolean> processSingle(TbContext ctx, TbMsg msg) {
EntityId from; EntityId from;
EntityId to; EntityId to;
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) { if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
@ -67,8 +81,25 @@ public class TbCheckRelationNode implements TbNode {
to = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId()); to = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId());
from = msg.getOriginator(); from = msg.getOriginator();
} }
withCallback(ctx.getRelationService().checkRelation(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON), return ctx.getRelationService().checkRelation(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON);
filterResult -> ctx.tellNext(msg, filterResult ? "True" : "False"), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); }
private ListenableFuture<Boolean> processList(TbContext ctx, TbMsg msg) {
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
return Futures.transformAsync(ctx.getRelationService()
.findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON), this::isEmptyList);
} else {
return Futures.transformAsync(ctx.getRelationService()
.findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), config.getRelationType(), RelationTypeGroup.COMMON), this::isEmptyList);
}
}
private ListenableFuture<Boolean> isEmptyList(List<EntityRelation> entityRelations) {
if (entityRelations.isEmpty()) {
return Futures.immediateFuture(false);
} else {
return Futures.immediateFuture(true);
}
} }
@Override @Override

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbCheckRelationNodeConfiguration.java

@ -18,10 +18,6 @@ package org.thingsboard.rule.engine.filter;
import lombok.Data; import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeConfiguration;
import org.thingsboard.server.common.data.relation.EntitySearchDirection; import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.msg.session.SessionMsgType;
import java.util.Arrays;
import java.util.List;
/** /**
* Created by ashvayka on 19.01.18. * Created by ashvayka on 19.01.18.
@ -33,12 +29,14 @@ public class TbCheckRelationNodeConfiguration implements NodeConfiguration<TbChe
private String entityId; private String entityId;
private String entityType; private String entityType;
private String relationType; private String relationType;
private boolean checkForSingleEntity;
@Override @Override
public TbCheckRelationNodeConfiguration defaultConfiguration() { public TbCheckRelationNodeConfiguration defaultConfiguration() {
TbCheckRelationNodeConfiguration configuration = new TbCheckRelationNodeConfiguration(); TbCheckRelationNodeConfiguration configuration = new TbCheckRelationNodeConfiguration();
configuration.setDirection(EntitySearchDirection.FROM.name()); configuration.setDirection(EntitySearchDirection.FROM.name());
configuration.setRelationType("Contains"); configuration.setRelationType("Contains");
configuration.setCheckForSingleEntity(true);
return configuration; return configuration;
} }
} }

8
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save