|
|
|
@ -19,17 +19,15 @@ import com.fasterxml.jackson.core.type.TypeReference; |
|
|
|
import com.fasterxml.jackson.databind.JsonNode; |
|
|
|
import com.google.common.util.concurrent.Futures; |
|
|
|
import com.google.common.util.concurrent.ListenableFuture; |
|
|
|
import com.google.common.util.concurrent.MoreExecutors; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.thingsboard.common.util.JacksonUtil; |
|
|
|
import org.thingsboard.script.api.RuleNodeScriptFactory; |
|
|
|
import org.thingsboard.script.api.TbScriptException; |
|
|
|
import org.thingsboard.script.api.tbel.TbelInvokeService; |
|
|
|
import org.thingsboard.server.common.data.StringUtils; |
|
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
|
import org.thingsboard.server.common.msg.TbMsg; |
|
|
|
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|
|
|
|
|
|
|
import javax.script.ScriptException; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.Collection; |
|
|
|
import java.util.Collections; |
|
|
|
@ -40,8 +38,8 @@ import java.util.Map; |
|
|
|
import java.util.Set; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
import static com.google.common.util.concurrent.MoreExecutors.directExecutor; |
|
|
|
|
|
|
|
@Slf4j |
|
|
|
public class RuleNodeTbelScriptEngine extends RuleNodeScriptEngine<TbelInvokeService, Object> { |
|
|
|
|
|
|
|
public RuleNodeTbelScriptEngine(TenantId tenantId, TbelInvokeService scriptInvokeService, String script, String... argNames) { |
|
|
|
@ -49,70 +47,74 @@ public class RuleNodeTbelScriptEngine extends RuleNodeScriptEngine<TbelInvokeSer |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected ListenableFuture<Boolean> executeFilterTransform(Object result) { |
|
|
|
if (result instanceof Boolean) { |
|
|
|
return Futures.immediateFuture((Boolean) result); |
|
|
|
protected Object[] prepareArgs(TbMsg msg) { |
|
|
|
Object[] args = new Object[3]; |
|
|
|
if (msg.getData() != null) { |
|
|
|
args[0] = JacksonUtil.fromString(msg.getData(), Object.class); |
|
|
|
} else { |
|
|
|
args[0] = new HashMap<>(); |
|
|
|
} |
|
|
|
return wrongResultType(result); |
|
|
|
args[1] = new HashMap<>(msg.getMetaData().getData()); |
|
|
|
args[2] = msg.getType(); |
|
|
|
return args; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected ListenableFuture<List<TbMsg>> executeUpdateTransform(TbMsg msg, Object result) { |
|
|
|
if (result instanceof Map) { |
|
|
|
return Futures.immediateFuture(Collections.singletonList(unbindMsg((Map) result, msg))); |
|
|
|
} else if (result instanceof Collection) { |
|
|
|
List<TbMsg> res = new ArrayList<>(); |
|
|
|
for (Object resObject : (Collection) result) { |
|
|
|
if (resObject instanceof Map) { |
|
|
|
res.add(unbindMsg((Map) resObject, msg)); |
|
|
|
protected List<TbMsg> executeUpdateTransform(TbMsg msg, Object result) { |
|
|
|
if (result instanceof Map msgData) { |
|
|
|
return Collections.singletonList(unbindMsg(msgData, msg)); |
|
|
|
} else if (result instanceof Collection resultCollection) { |
|
|
|
List<TbMsg> res = new ArrayList<>(resultCollection.size()); |
|
|
|
for (Object resObject : resultCollection) { |
|
|
|
if (resObject instanceof Map msgData) { |
|
|
|
res.add(unbindMsg(msgData, msg)); |
|
|
|
} else { |
|
|
|
return wrongResultType(resObject); |
|
|
|
throw wrongResultType(resObject); |
|
|
|
} |
|
|
|
} |
|
|
|
return Futures.immediateFuture(res); |
|
|
|
return res; |
|
|
|
} |
|
|
|
return wrongResultType(result); |
|
|
|
throw wrongResultType(result); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected ListenableFuture<TbMsg> executeGenerateTransform(TbMsg prevMsg, Object result) { |
|
|
|
if (result instanceof Map) { |
|
|
|
return Futures.immediateFuture(unbindMsg((Map) result, prevMsg)); |
|
|
|
protected TbMsg executeGenerateTransform(TbMsg prevMsg, Object result) { |
|
|
|
if (result instanceof Map msgData) { |
|
|
|
return unbindMsg(msgData, prevMsg); |
|
|
|
} |
|
|
|
return wrongResultType(result); |
|
|
|
throw wrongResultType(result); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected ListenableFuture<String> executeToStringTransform(Object result) { |
|
|
|
if (result instanceof String) { |
|
|
|
return Futures.immediateFuture((String) result); |
|
|
|
} else { |
|
|
|
return Futures.immediateFuture(JacksonUtil.toString(result)); |
|
|
|
protected boolean executeFilterTransform(Object result) { |
|
|
|
if (result instanceof Boolean b) { |
|
|
|
return b; |
|
|
|
} |
|
|
|
throw wrongResultType(result); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected ListenableFuture<Set<String>> executeSwitchTransform(Object result) { |
|
|
|
if (result instanceof String) { |
|
|
|
return Futures.immediateFuture(Collections.singleton((String) result)); |
|
|
|
} else if (result instanceof Collection) { |
|
|
|
Set<String> res = new HashSet<>(); |
|
|
|
for (Object resObject : (Collection) result) { |
|
|
|
if (resObject instanceof String) { |
|
|
|
res.add((String) resObject); |
|
|
|
protected Set<String> executeSwitchTransform(Object result) { |
|
|
|
if (result instanceof String str) { |
|
|
|
return Collections.singleton(str); |
|
|
|
} |
|
|
|
if (result instanceof Collection<?> resultCollection) { |
|
|
|
Set<String> res = new HashSet<>(resultCollection.size()); |
|
|
|
for (Object resObject : resultCollection) { |
|
|
|
if (resObject instanceof String str) { |
|
|
|
res.add(str); |
|
|
|
} else { |
|
|
|
return wrongResultType(resObject); |
|
|
|
throw wrongResultType(resObject); |
|
|
|
} |
|
|
|
} |
|
|
|
return Futures.immediateFuture(res); |
|
|
|
return res; |
|
|
|
} |
|
|
|
return wrongResultType(result); |
|
|
|
throw wrongResultType(result); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public ListenableFuture<JsonNode> executeJsonAsync(TbMsg msg) { |
|
|
|
return Futures.transform(executeScriptAsync(msg), JacksonUtil::valueToTree, MoreExecutors.directExecutor()); |
|
|
|
|
|
|
|
return Futures.transform(executeScriptAsync(msg), JacksonUtil::valueToTree, directExecutor()); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@ -121,16 +123,8 @@ public class RuleNodeTbelScriptEngine extends RuleNodeScriptEngine<TbelInvokeSer |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected Object[] prepareArgs(TbMsg msg) { |
|
|
|
Object[] args = new Object[3]; |
|
|
|
if (msg.getData() != null) { |
|
|
|
args[0] = JacksonUtil.fromString(msg.getData(), Object.class); |
|
|
|
} else { |
|
|
|
args[0] = new HashMap<>(); |
|
|
|
} |
|
|
|
args[1] = new HashMap<>(msg.getMetaData().getData()); |
|
|
|
args[2] = msg.getType(); |
|
|
|
return args; |
|
|
|
protected String executeToStringTransform(Object result) { |
|
|
|
return result instanceof String str ? str : JacksonUtil.toString(result); |
|
|
|
} |
|
|
|
|
|
|
|
private static TbMsg unbindMsg(Map msgData, TbMsg msg) { |
|
|
|
@ -142,12 +136,12 @@ public class RuleNodeTbelScriptEngine extends RuleNodeScriptEngine<TbelInvokeSer |
|
|
|
} |
|
|
|
if (msgData.containsKey(RuleNodeScriptFactory.METADATA)) { |
|
|
|
Object msgMetadataObj = msgData.get(RuleNodeScriptFactory.METADATA); |
|
|
|
if (msgMetadataObj instanceof Map) { |
|
|
|
metadata = ((Map<?, ?>) msgMetadataObj).entrySet().stream().filter(e -> e.getValue() != null) |
|
|
|
if (msgMetadataObj instanceof Map<?, ?> msgMetadataObjAsMap) { |
|
|
|
metadata = msgMetadataObjAsMap.entrySet().stream() |
|
|
|
.filter(e -> e.getValue() != null) |
|
|
|
.collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString())); |
|
|
|
} else { |
|
|
|
metadata = JacksonUtil.convertValue(msgMetadataObj, new TypeReference<>() { |
|
|
|
}); |
|
|
|
metadata = JacksonUtil.convertValue(msgMetadataObj, new TypeReference<>() {}); |
|
|
|
} |
|
|
|
} |
|
|
|
if (msgData.containsKey(RuleNodeScriptFactory.MSG_TYPE)) { |
|
|
|
@ -155,7 +149,7 @@ public class RuleNodeTbelScriptEngine extends RuleNodeScriptEngine<TbelInvokeSer |
|
|
|
} |
|
|
|
String newData = data != null ? data : msg.getData(); |
|
|
|
TbMsgMetaData newMetadata = metadata != null ? new TbMsgMetaData(metadata) : msg.getMetaData().copy(); |
|
|
|
String newMessageType = !StringUtils.isEmpty(messageType) ? messageType : msg.getType(); |
|
|
|
String newMessageType = StringUtils.isNotEmpty(messageType) ? messageType : msg.getType(); |
|
|
|
return msg.transform() |
|
|
|
.type(newMessageType) |
|
|
|
.metaData(newMetadata) |
|
|
|
@ -163,13 +157,13 @@ public class RuleNodeTbelScriptEngine extends RuleNodeScriptEngine<TbelInvokeSer |
|
|
|
.build(); |
|
|
|
} |
|
|
|
|
|
|
|
private static <T> ListenableFuture<T> wrongResultType(Object result) { |
|
|
|
private TbScriptException wrongResultType(Object result) { |
|
|
|
String className = toClassName(result); |
|
|
|
log.warn("Wrong result type: {}", className); |
|
|
|
return Futures.immediateFailedFuture(new ScriptException("Wrong result type: " + className)); |
|
|
|
return new TbScriptException(scriptId, TbScriptException.ErrorCode.RUNTIME, null, new ClassCastException("Wrong result type: " + className)); |
|
|
|
} |
|
|
|
|
|
|
|
private static String toClassName(Object result) { |
|
|
|
return result != null ? result.getClass().getSimpleName() : "null"; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|