Feature/relation nodes (#1414)
* modify TbCheckRelationNode * fix TbCheckRelationNode * modify TbDeleteRelationNode * fix rule-nodes description * fix rule-nodes ui * fix relation action nodes
This commit is contained in:
parent
94827253e4
commit
b966abb3e6
@ -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.page.TextPageData;
|
||||
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.RelationTypeGroup;
|
||||
import org.thingsboard.server.common.msg.TbMsg;
|
||||
import org.thingsboard.server.dao.asset.AssetService;
|
||||
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.entityview.EntityViewService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -84,7 +87,7 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
|
||||
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));
|
||||
}
|
||||
|
||||
@ -111,7 +114,7 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
|
||||
});
|
||||
}
|
||||
|
||||
protected void processSearchDirection(TbMsg msg, EntityContainer entityContainer) {
|
||||
protected void processSingleSearchDirection(TbMsg msg, EntityContainer entityContainer) {
|
||||
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
|
||||
fromId = EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString());
|
||||
toId = msg.getOriginator();
|
||||
@ -121,6 +124,14 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@AllArgsConstructor
|
||||
private static class Entitykey {
|
||||
|
||||
@ -65,7 +65,7 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
|
||||
}
|
||||
|
||||
private ListenableFuture<Boolean> createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
|
||||
processSearchDirection(msg, entityContainer);
|
||||
processSingleSearchDirection(msg, entityContainer);
|
||||
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON),
|
||||
result -> {
|
||||
if (!result) {
|
||||
|
||||
@ -25,16 +25,22 @@ import org.thingsboard.rule.engine.api.TbNodeException;
|
||||
import org.thingsboard.rule.engine.api.util.TbNodeUtils;
|
||||
import org.thingsboard.rule.engine.util.EntityContainer;
|
||||
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.msg.TbMsg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RuleNode(
|
||||
type = ComponentType.ACTION,
|
||||
name = "delete relation",
|
||||
configClazz = TbDeleteRelationNodeConfiguration.class,
|
||||
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.",
|
||||
nodeDescription = "Finds target Entity by entity name pattern and then delete a relation to Originator Entity by type and direction" +
|
||||
" 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"},
|
||||
configDirective ="tbActionNodeDeleteRelationConfig",
|
||||
icon = "remove_circle"
|
||||
@ -52,22 +58,52 @@ public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteR
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
|
||||
return deleteIfExist(ctx, msg, entityContainer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private ListenableFuture<Boolean> deleteIfExist(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
|
||||
processSearchDirection(msg, entityContainer);
|
||||
@Override
|
||||
protected ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
|
||||
return processSingle(ctx, msg, entityContainer);
|
||||
}
|
||||
|
||||
private ListenableFuture<Boolean> processList(TbContext ctx, TbMsg msg) {
|
||||
return Futures.transformAsync(processListSearchDirection(ctx, msg), entityRelations -> {
|
||||
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) {
|
||||
processSingleSearchDirection(msg, entityContainer);
|
||||
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON),
|
||||
result -> {
|
||||
if (result) {
|
||||
return processDeleteRelation(ctx);
|
||||
return processSingleDeleteRelation(ctx);
|
||||
}
|
||||
return Futures.immediateFuture(true);
|
||||
});
|
||||
}
|
||||
|
||||
private ListenableFuture<Boolean> processDeleteRelation(TbContext ctx) {
|
||||
private ListenableFuture<Boolean> processSingleDeleteRelation(TbContext ctx) {
|
||||
return ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON);
|
||||
}
|
||||
|
||||
|
||||
@ -22,10 +22,12 @@ import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||
@Data
|
||||
public class TbDeleteRelationNodeConfiguration extends TbAbstractRelationActionNodeConfiguration implements NodeConfiguration<TbDeleteRelationNodeConfiguration> {
|
||||
|
||||
private boolean deleteForSingleEntity;
|
||||
|
||||
@Override
|
||||
public TbDeleteRelationNodeConfiguration defaultConfiguration() {
|
||||
TbDeleteRelationNodeConfiguration configuration = new TbDeleteRelationNodeConfiguration();
|
||||
configuration.setDeleteForSingleEntity(true);
|
||||
configuration.setDirection(EntitySearchDirection.FROM.name());
|
||||
configuration.setRelationType("Contains");
|
||||
configuration.setEntityNamePattern("");
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
*/
|
||||
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 org.thingsboard.rule.engine.api.RuleNode;
|
||||
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.EntityIdFactory;
|
||||
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.RelationTypeGroup;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -43,8 +45,10 @@ import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
|
||||
name = "check relation",
|
||||
configClazz = TbCheckRelationNodeConfiguration.class,
|
||||
relationTypes = {"True", "False"},
|
||||
nodeDescription = "Checks the relation from the selected entity to 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.",
|
||||
nodeDescription = "Checks the relation from the selected entity to the originator of the message by type and direction" +
|
||||
" 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"},
|
||||
configDirective = "tbFilterNodeCheckRelationConfig")
|
||||
public class TbCheckRelationNode implements TbNode {
|
||||
@ -58,6 +62,16 @@ public class TbCheckRelationNode implements TbNode {
|
||||
|
||||
@Override
|
||||
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 to;
|
||||
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) {
|
||||
@ -67,8 +81,25 @@ public class TbCheckRelationNode implements TbNode {
|
||||
to = EntityIdFactory.getByTypeAndId(config.getEntityType(), config.getEntityId());
|
||||
from = msg.getOriginator();
|
||||
}
|
||||
withCallback(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());
|
||||
return ctx.getRelationService().checkRelation(ctx.getTenantId(), from, to, config.getRelationType(), RelationTypeGroup.COMMON);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@ -18,10 +18,6 @@ package org.thingsboard.rule.engine.filter;
|
||||
import lombok.Data;
|
||||
import org.thingsboard.rule.engine.api.NodeConfiguration;
|
||||
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.
|
||||
@ -33,12 +29,14 @@ public class TbCheckRelationNodeConfiguration implements NodeConfiguration<TbChe
|
||||
private String entityId;
|
||||
private String entityType;
|
||||
private String relationType;
|
||||
private boolean checkForSingleEntity;
|
||||
|
||||
@Override
|
||||
public TbCheckRelationNodeConfiguration defaultConfiguration() {
|
||||
TbCheckRelationNodeConfiguration configuration = new TbCheckRelationNodeConfiguration();
|
||||
configuration.setDirection(EntitySearchDirection.FROM.name());
|
||||
configuration.setRelationType("Contains");
|
||||
configuration.setCheckForSingleEntity(true);
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user