Improve config of 'originator fields' node. Add UI config for 'originator fields' and 'check relation' nodes.

This commit is contained in:
Igor Kulikov 2018-06-01 13:49:09 +03:00
parent 7a687f373c
commit 9ea4fcce6f
6 changed files with 90 additions and 41 deletions

View File

@ -15,10 +15,18 @@
*/ */
package org.thingsboard.server.common.data; package org.thingsboard.server.common.data;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import java.io.IOException;
/** /**
* Created by ashvayka on 01.06.18. * Created by ashvayka on 01.06.18.
*/ */
@ -26,13 +34,54 @@ import org.thingsboard.server.common.data.id.EntityId;
@AllArgsConstructor @AllArgsConstructor
public class EntityFieldsData { public class EntityFieldsData {
public static final String DEFAULT = "default"; private static final ObjectMapper mapper = new ObjectMapper();
private final EntityId entityId; static {
private final String name; SimpleModule entityFieldsModule = new SimpleModule("EntityFieldsModule", new Version(1, 0, 0, null, null, null));
private final String type; entityFieldsModule.addSerializer(EntityId.class, new EntityIdFieldSerializer());
mapper.disable(MapperFeature.USE_ANNOTATIONS);
public EntityFieldsData(EntityId entityId, String name) { mapper.registerModule(entityFieldsModule);
this(entityId, name, DEFAULT);
} }
private ObjectNode fieldsData;
public EntityFieldsData(BaseData data) {
fieldsData = mapper.valueToTree(data);
}
public String getFieldValue(String field) {
String[] fieldsTree = field.split("\\.");
JsonNode current = fieldsData;
for (String key : fieldsTree) {
if (current.has(key)) {
current = current.get(key);
} else {
current = null;
break;
}
}
if (current != null) {
if (current.isValueNode()) {
return current.asText();
} else {
try {
return mapper.writeValueAsString(current);
} catch (JsonProcessingException e) {
return null;
}
}
} else {
return null;
}
}
private static class EntityIdFieldSerializer extends JsonSerializer<EntityId> {
@Override
public void serialize(EntityId value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeObject(value.getId());
}
}
} }

View File

@ -44,7 +44,9 @@ import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
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 originator of the message by type and direction",
nodeDetails = "If incoming MessageType is expected - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.") nodeDetails = "If incoming MessageType is expected - 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 { public class TbCheckRelationNode implements TbNode {
private TbCheckRelationNodeConfiguration config; private TbCheckRelationNodeConfiguration config;

View File

@ -18,21 +18,21 @@ package org.thingsboard.rule.engine.metadata;
import lombok.Data; import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration; import org.thingsboard.rule.engine.api.NodeConfiguration;
import java.util.HashMap;
import java.util.Map;
@Data @Data
public class TbGetOriginatorFieldsConfiguration implements NodeConfiguration<TbGetOriginatorFieldsConfiguration> { public class TbGetOriginatorFieldsConfiguration implements NodeConfiguration<TbGetOriginatorFieldsConfiguration> {
private boolean fetchName; private Map<String, String> fieldsMapping;
private String nameMetadataKey;
private boolean fetchType;
private String typeMetadataKey;
@Override @Override
public TbGetOriginatorFieldsConfiguration defaultConfiguration() { public TbGetOriginatorFieldsConfiguration defaultConfiguration() {
TbGetOriginatorFieldsConfiguration configuration = new TbGetOriginatorFieldsConfiguration(); TbGetOriginatorFieldsConfiguration configuration = new TbGetOriginatorFieldsConfiguration();
configuration.setFetchName(true); Map<String, String> fieldsMapping = new HashMap<>();
configuration.setNameMetadataKey("entityName"); fieldsMapping.put("name", "originatorName");
configuration.setFetchType(true); fieldsMapping.put("type", "originatorType");
configuration.setTypeMetadataKey("entityType"); configuration.setFieldsMapping(fieldsMapping);
return configuration; return configuration;
} }
} }

View File

@ -18,11 +18,7 @@ package org.thingsboard.rule.engine.metadata;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; 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.*;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
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.EntitiesFieldsAsyncLoader; import org.thingsboard.rule.engine.util.EntitiesFieldsAsyncLoader;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
@ -37,10 +33,12 @@ import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback;
*/ */
@Slf4j @Slf4j
@RuleNode(type = ComponentType.ENRICHMENT, @RuleNode(type = ComponentType.ENRICHMENT,
name = "entity fields", name = "originator fields",
configClazz = TbGetOriginatorFieldsConfiguration.class, configClazz = TbGetOriginatorFieldsConfiguration.class,
nodeDescription = "Add Message Originator Name and Type into Message Metadata", nodeDescription = "Add Message Originator fields values into Message Metadata",
nodeDetails = "If originator is Asset, Device or Alarm, both name and type are added. In all other cases type will always be \"default\"") nodeDetails = "Will fetch fields values specified in mapping. If specified field is not part of originator fields it will be ignored.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbEnrichmentNodeOriginatorFieldsConfig")
public class TbGetOriginatorFieldsNode implements TbNode { public class TbGetOriginatorFieldsNode implements TbNode {
private TbGetOriginatorFieldsConfiguration config; private TbGetOriginatorFieldsConfiguration config;
@ -61,17 +59,17 @@ public class TbGetOriginatorFieldsNode implements TbNode {
} }
private ListenableFuture<Void> putEntityFields(TbContext ctx, EntityId entityId, TbMsg msg) { private ListenableFuture<Void> putEntityFields(TbContext ctx, EntityId entityId, TbMsg msg) {
if (!config.isFetchName() && !config.isFetchType()) { if (config.getFieldsMapping().isEmpty()) {
return Futures.immediateFuture(null); return Futures.immediateFuture(null);
} else { } else {
return Futures.transform(EntitiesFieldsAsyncLoader.findAsync(ctx, entityId), return Futures.transform(EntitiesFieldsAsyncLoader.findAsync(ctx, entityId),
data -> { data -> {
if (config.isFetchName()) { config.getFieldsMapping().forEach((field, metaKey) -> {
msg.getMetaData().putValue(config.getNameMetadataKey(), data.getName()); String val = data.getFieldValue(field);
} if (val != null) {
if (config.isFetchType()) { msg.getMetaData().putValue(metaKey, val);
msg.getMetaData().putValue(config.getTypeMetadataKey(), data.getType()); }
} });
return null; return null;
} }
); );

View File

@ -38,25 +38,25 @@ public class EntitiesFieldsAsyncLoader {
switch (original.getEntityType()) { switch (original.getEntityType()) {
case TENANT: case TENANT:
return getAsync(ctx.getTenantService().findTenantByIdAsync((TenantId) original), return getAsync(ctx.getTenantService().findTenantByIdAsync((TenantId) original),
t -> new EntityFieldsData(t.getId(), t.getName())); t -> new EntityFieldsData(t));
case CUSTOMER: case CUSTOMER:
return getAsync(ctx.getCustomerService().findCustomerByIdAsync((CustomerId) original), return getAsync(ctx.getCustomerService().findCustomerByIdAsync((CustomerId) original),
t -> new EntityFieldsData(t.getId(), t.getName())); t -> new EntityFieldsData(t));
case USER: case USER:
return getAsync(ctx.getUserService().findUserByIdAsync((UserId) original), return getAsync(ctx.getUserService().findUserByIdAsync((UserId) original),
t -> new EntityFieldsData(t.getId(), t.getName())); t -> new EntityFieldsData(t));
case ASSET: case ASSET:
return getAsync(ctx.getAssetService().findAssetByIdAsync((AssetId) original), return getAsync(ctx.getAssetService().findAssetByIdAsync((AssetId) original),
t -> new EntityFieldsData(t.getId(), t.getName(), t.getType())); t -> new EntityFieldsData(t));
case DEVICE: case DEVICE:
return getAsync(ctx.getDeviceService().findDeviceByIdAsync((DeviceId) original), return getAsync(ctx.getDeviceService().findDeviceByIdAsync((DeviceId) original),
t -> new EntityFieldsData(t.getId(), t.getName(), t.getType())); t -> new EntityFieldsData(t));
case ALARM: case ALARM:
return getAsync(ctx.getAlarmService().findAlarmByIdAsync((AlarmId) original), return getAsync(ctx.getAlarmService().findAlarmByIdAsync((AlarmId) original),
t -> new EntityFieldsData(t.getId(), t.getName(), t.getType())); t -> new EntityFieldsData(t));
case RULE_CHAIN: case RULE_CHAIN:
return getAsync(ctx.getRuleChainService().findRuleChainByIdAsync((RuleChainId) original), return getAsync(ctx.getRuleChainService().findRuleChainByIdAsync((RuleChainId) original),
t -> new EntityFieldsData(t.getId(), t.getName())); t -> new EntityFieldsData(t));
default: default:
return Futures.immediateFailedFuture(new TbNodeException("Unexpected original EntityType " + original)); return Futures.immediateFailedFuture(new TbNodeException("Unexpected original EntityType " + original));
} }