diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java index e9d38c91fb..d20c8d1e72 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetEntityDetailsNode.java @@ -15,6 +15,8 @@ */ package org.thingsboard.rule.engine.metadata; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -34,9 +36,9 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; import java.lang.reflect.Type; import java.util.Map; -import java.util.concurrent.ExecutionException; import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; +import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; @Slf4j public abstract class TbAbstractGetEntityDetailsNode implements TbNode { @@ -54,19 +56,20 @@ public abstract class TbAbstractGetEntityDetailsNode ctx.tellNext(m, SUCCESS), + t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); } @Override - public void destroy() {} + public void destroy() { + } protected abstract C loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException; - protected abstract TbMsg getDetails(TbContext ctx, TbMsg msg); + protected abstract ListenableFuture getDetails(TbContext ctx, TbMsg msg); + + protected abstract ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg); protected MessageData getDataAsJson(TbMsg msg) { if (this.config.isAddToMetadata()) { @@ -76,25 +79,56 @@ public abstract class TbAbstractGetEntityDetailsNode metadataMap = gson.fromJson(resultObject.toString(), TYPE); - return ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData()); + protected ListenableFuture getTbMsgListenableFuture(TbContext ctx, TbMsg msg, MessageData messageData, String prefix) { + if (!this.config.getDetailsList().isEmpty()) { + ListenableFuture resultObject = null; + ListenableFuture contactBasedListenableFuture = getContactBasedListenableFuture(ctx, msg); + for (EntityDetails entityDetails : this.config.getDetailsList()) { + resultObject = addContactProperties(messageData.getData(), contactBasedListenableFuture, entityDetails, prefix); + } + return transformMsg(ctx, msg, resultObject, messageData); } else { - return ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(resultObject)); + return Futures.immediateFuture(msg); } } - protected JsonElement addContactProperties(JsonElement data, ContactBased entity, EntityDetails entityDetails, String prefix) { + private ListenableFuture transformMsg(TbContext ctx, TbMsg msg, ListenableFuture propertiesFuture, MessageData messageData) { + return Futures.transformAsync(propertiesFuture, jsonElement -> { + if (jsonElement != null) { + if (messageData.getDataType().equals("metadata")) { + Map metadataMap = gson.fromJson(jsonElement.toString(), TYPE); + return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData())); + } else { + return Futures.immediateFuture(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(jsonElement))); + } + } else { + return Futures.immediateFuture(null); + } + }); + } + + private ListenableFuture addContactProperties(JsonElement data, ListenableFuture entityFuture, EntityDetails entityDetails, String prefix) { + return Futures.transformAsync(entityFuture, contactBased -> { + if (contactBased != null) { + return Futures.immediateFuture(setProperties(contactBased, data, entityDetails, prefix)); + } else { + return Futures.immediateFuture(null); + } + }); + } + + private JsonElement setProperties(ContactBased entity, JsonElement data, EntityDetails entityDetails, String prefix) { JsonObject dataAsObject = data.getAsJsonObject(); switch (entityDetails) { case ADDRESS: - if (entity.getAddress() != null) + if (entity.getAddress() != null) { dataAsObject.addProperty(prefix + "address", entity.getAddress()); + } break; case ADDRESS2: - if (entity.getAddress2() != null) + if (entity.getAddress2() != null) { dataAsObject.addProperty(prefix + "address2", entity.getAddress2()); + } break; case CITY: if (entity.getCity() != null) dataAsObject.addProperty(prefix + "city", entity.getCity()); @@ -104,16 +138,24 @@ public abstract class TbAbstractGetEntityDetailsNode getDetails(TbContext ctx, TbMsg msg) { + return getTbMsgListenableFuture(ctx, msg, getDataAsJson(msg), CUSTOMER_PREFIX); } - private TbMsg getCustomerTbMsg(TbContext ctx, TbMsg msg, MessageData messageData) { - JsonElement resultObject = null; - if (!config.getDetailsList().isEmpty()) { - for (EntityDetails entityDetails : config.getDetailsList()) { - resultObject = addContactProperties(messageData.getData(), getCustomer(ctx, msg), entityDetails, CUSTOMER_PREFIX); + @Override + protected ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg) { + return Futures.transformAsync(getCustomer(ctx, msg), customer -> { + if (customer != null) { + return Futures.immediateFuture(customer); + } else { + return Futures.immediateFuture(null); } - return transformMsg(ctx, msg, resultObject, messageData); - } else { - return msg; - } + }); } - private Customer getCustomer(TbContext ctx, TbMsg msg) { + private ListenableFuture getCustomer(TbContext ctx, TbMsg msg) { switch (msg.getOriginator().getEntityType()) { case DEVICE: - Device device = ctx.getDeviceService().findDeviceById(ctx.getTenantId(), new DeviceId(msg.getOriginator().getId())); - if (!device.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerById(ctx.getTenantId(), device.getCustomerId()); - } else { - throw new RuntimeException("Device with name '" + device.getName() + "' is not assigned to Customer."); - } + return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(msg.getOriginator().getId())), device -> { + if (device != null) { + if (!device.getCustomerId().isNullUid()) { + return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), device.getCustomerId()); + } else { + throw new RuntimeException("Device with name '" + device.getName() + "' is not assigned to Customer."); + } + } else { + return Futures.immediateFuture(null); + } + }); case ASSET: - Asset asset = ctx.getAssetService().findAssetById(ctx.getTenantId(), new AssetId(msg.getOriginator().getId())); - if (!asset.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerById(ctx.getTenantId(), asset.getCustomerId()); - } else { - throw new RuntimeException("Asset with name '" + asset.getName() + "' is not assigned to Customer."); - } + return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(msg.getOriginator().getId())), asset -> { + if (asset != null) { + if (!asset.getCustomerId().isNullUid()) { + return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), asset.getCustomerId()); + } else { + throw new RuntimeException("Asset with name '" + asset.getName() + "' is not assigned to Customer."); + } + } else { + return Futures.immediateFuture(null); + } + }); case ENTITY_VIEW: - EntityView entityView = ctx.getEntityViewService().findEntityViewById(ctx.getTenantId(), new EntityViewId(msg.getOriginator().getId())); - if (!entityView.getCustomerId().isNullUid()) { - return ctx.getCustomerService().findCustomerById(ctx.getTenantId(), entityView.getCustomerId()); - } else { - throw new RuntimeException("EntityView with name '" + entityView.getName() + "' is not assigned to Customer."); - } + return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(msg.getOriginator().getId())), entityView -> { + if (entityView != null) { + if (!entityView.getCustomerId().isNullUid()) { + return ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), entityView.getCustomerId()); + } else { + throw new RuntimeException("EntityView with name '" + entityView.getName() + "' is not assigned to Customer."); + } + } else { + return Futures.immediateFuture(null); + } + }); default: throw new RuntimeException("Entity with entityType '" + msg.getOriginator().getEntityType() + "' is not supported."); } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java index 93b8f059f7..f029da29af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTenantDetailsNode.java @@ -15,17 +15,15 @@ */ package org.thingsboard.rule.engine.metadata; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +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; 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.util.EntityDetails; import org.thingsboard.server.common.data.ContactBased; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -49,20 +47,18 @@ public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode getDetails(TbContext ctx, TbMsg msg) { + return getTbMsgListenableFuture(ctx, msg, getDataAsJson(msg), TENANT_PREFIX); } - private TbMsg getTenantTbMsg(TbContext ctx, TbMsg msg, MessageData messageData) { - JsonElement resultObject = null; - Tenant tenant = ctx.getTenantService().findTenantById(ctx.getTenantId()); - if (!config.getDetailsList().isEmpty()) { - for (EntityDetails entityDetails : config.getDetailsList()) { - resultObject = addContactProperties(messageData.getData(), tenant, entityDetails, TENANT_PREFIX); + @Override + protected ListenableFuture getContactBasedListenableFuture(TbContext ctx, TbMsg msg) { + return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), ctx.getTenantId()), tenant -> { + if (tenant != null) { + return Futures.immediateFuture(tenant); + } else { + return Futures.immediateFuture(null); } - return transformMsg(ctx, msg, resultObject, messageData); - } else { - return msg; - } + }); } }