|
|
|
@ -32,59 +32,77 @@ import org.thingsboard.server.common.msg.TbMsg; |
|
|
|
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
|
import java.util.regex.Pattern; |
|
|
|
|
|
|
|
@Slf4j |
|
|
|
@RuleNode( |
|
|
|
type = ComponentType.TRANSFORMATION, |
|
|
|
name = "copy from metadata to msg", |
|
|
|
configClazz = TbCopyFromMdToMsgNodeConfiguration.class, |
|
|
|
nodeDescription = "Copies the msg metadata keys to msg data with specified key names selected in the list", |
|
|
|
nodeDetails = "Will fetch fields values specified in list. If specified field is not part of msg metadata fields it will be ignored." + |
|
|
|
name = "copy keys", |
|
|
|
configClazz = TbCopyKeysNodeConfiguration.class, |
|
|
|
nodeDescription = "Copies the msg or metadata keys with specified key names selected in the list", |
|
|
|
nodeDetails = "Will fetch fields values specified in list. If specified field is not part of msg or metadata fields it will be ignored." + |
|
|
|
"If the msg is not a JSON object returns the incoming message as outbound message with <code>Failure</code> chain, " + |
|
|
|
"otherwise returns transformed messages via <code>Success</code> chain", |
|
|
|
uiResources = {"static/rulenode/rulenode-core-config.js"}, |
|
|
|
configDirective = "tbTransformationNodeCopyFromMdToMsgConfig", |
|
|
|
icon = "functions" |
|
|
|
configDirective = "tbTransformationNodeCopyKeysConfig", |
|
|
|
icon = "content_copy" |
|
|
|
) |
|
|
|
public class TbCopyFromMdToMsgNode implements TbNode { |
|
|
|
public class TbCopyKeysNode implements TbNode { |
|
|
|
|
|
|
|
TbCopyFromMdToMsgNodeConfiguration config; |
|
|
|
TbCopyKeysNodeConfiguration config; |
|
|
|
|
|
|
|
@Override |
|
|
|
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
|
|
|
this.config = TbNodeUtils.convert(configuration, TbCopyFromMdToMsgNodeConfiguration.class); |
|
|
|
this.config = TbNodeUtils.convert(configuration, TbCopyKeysNodeConfiguration.class); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { |
|
|
|
processCopy(ctx, msg); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void destroy() { |
|
|
|
} |
|
|
|
|
|
|
|
private void processCopy(TbContext ctx, TbMsg msg) { |
|
|
|
List<String> metadataMsgKeys = config.getMetadataMsgKeys(); |
|
|
|
if (CollectionUtils.isEmpty(metadataMsgKeys)) { |
|
|
|
List<String> keys = config.getKeys(); |
|
|
|
if (CollectionUtils.isEmpty(keys)) { |
|
|
|
ctx.tellSuccess(msg); |
|
|
|
} else { |
|
|
|
JsonNode dataNode = JacksonUtil.toJsonNode(msg.getData()); |
|
|
|
if (dataNode.isObject()) { |
|
|
|
ObjectNode msgData = (ObjectNode) dataNode; |
|
|
|
TbMsgMetaData metaData = msg.getMetaData(); |
|
|
|
metadataMsgKeys.forEach(metadataKey -> { |
|
|
|
String value = metaData.getValue(metadataKey); |
|
|
|
if (!StringUtils.isEmpty(value)) { |
|
|
|
msgData.put(metadataKey, value); |
|
|
|
} |
|
|
|
TbMsgMetaData metaData = msg.getMetaData(); |
|
|
|
String msgData = msg.getData(); |
|
|
|
JsonNode dataNode = JacksonUtil.toJsonNode(msgData); |
|
|
|
if (!dataNode.isObject()) { |
|
|
|
ctx.tellFailure(msg, new RuntimeException("Msg data is not a JSON Object!")); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (config.isFromMetadata()) { |
|
|
|
ObjectNode msgDataNode = (ObjectNode) dataNode; |
|
|
|
Map<String, String> metaDataMap = metaData.getData(); |
|
|
|
keys.forEach(key -> { |
|
|
|
Pattern pattern = Pattern.compile(key); |
|
|
|
metaDataMap.forEach((keyMetaData, valueMetaData) -> { |
|
|
|
if (pattern.matcher(keyMetaData).matches()) { |
|
|
|
if (!StringUtils.isEmpty(valueMetaData)) { |
|
|
|
msgDataNode.put(keyMetaData, valueMetaData); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, JacksonUtil.toString(msgData))); |
|
|
|
msgData = JacksonUtil.toString(msgDataNode); |
|
|
|
} else { |
|
|
|
ctx.tellFailure(msg, new RuntimeException("Msg data is not a JSON Object!")); |
|
|
|
keys.forEach(key -> { |
|
|
|
Pattern pattern = Pattern.compile(key); |
|
|
|
dataNode.fields().forEachRemaining(entry -> { |
|
|
|
String keyData = entry.getKey(); |
|
|
|
if (pattern.matcher(keyData).matches()) { |
|
|
|
metaData.putValue(keyData, String.valueOf(entry.getValue())); |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
ctx.tellSuccess(TbMsg.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msgData)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void destroy() { |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|