committed by
Andrew Shvayka
8 changed files with 466 additions and 4 deletions
@ -0,0 +1,95 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.metadata; |
|||
|
|||
import com.google.gson.Gson; |
|||
import com.google.gson.JsonElement; |
|||
import com.google.gson.JsonParser; |
|||
import com.google.gson.reflect.TypeToken; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
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.server.common.msg.TbMsg; |
|||
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; |
|||
|
|||
@Slf4j |
|||
public abstract class TbAbstractGetEntityDetailsNode<C extends TbAbstractGetEntityDetailsNodeConfiguration> implements TbNode { |
|||
|
|||
private static final Gson gson = new Gson(); |
|||
private static final JsonParser jsonParser = new JsonParser(); |
|||
private static final Type TYPE = new TypeToken<Map<String, String>>() {}.getType(); |
|||
|
|||
protected C config; |
|||
|
|||
@Override |
|||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
|||
this.config = loadGetEntityDetailsNodeConfiguration(configuration); |
|||
} |
|||
|
|||
@Override |
|||
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException { |
|||
try { |
|||
ctx.tellNext(getDetails(ctx, msg), SUCCESS); |
|||
} catch (Exception e) { |
|||
ctx.tellFailure(msg, e); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() {} |
|||
|
|||
protected abstract C loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException; |
|||
|
|||
protected abstract TbMsg getDetails(TbContext ctx, TbMsg msg); |
|||
|
|||
protected MessageData getDataAsJson(TbMsg msg) { |
|||
if (this.config.isAddToMetadata()) { |
|||
return new MessageData(gson.toJsonTree(msg.getMetaData().getData(), TYPE), "metadata"); |
|||
} else { |
|||
return new MessageData(jsonParser.parse(msg.getData()), "data"); |
|||
} |
|||
} |
|||
|
|||
protected TbMsg transformMsg(TbContext ctx, TbMsg msg, JsonElement resultObject, MessageData messageData) { |
|||
if (messageData.getDataType().equals("metadata")) { |
|||
Map<String, String> metadataMap = gson.fromJson(resultObject.toString(), TYPE); |
|||
return ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), new TbMsgMetaData(metadataMap), msg.getData()); |
|||
} else { |
|||
return ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), gson.toJson(resultObject)); |
|||
} |
|||
} |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
protected static class MessageData { |
|||
|
|||
private JsonElement data; |
|||
private String dataType; |
|||
|
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.metadata; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.rule.engine.util.EntityDetails; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public abstract class TbAbstractGetEntityDetailsNodeConfiguration { |
|||
|
|||
|
|||
private List<EntityDetails> detailsList; |
|||
|
|||
private boolean addToMetadata; |
|||
|
|||
} |
|||
@ -0,0 +1,142 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.metadata; |
|||
|
|||
import com.google.gson.JsonElement; |
|||
import com.google.gson.JsonObject; |
|||
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.Customer; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.EntityView; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EntityViewId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
|
|||
@Slf4j |
|||
@RuleNode(type = ComponentType.ENRICHMENT, |
|||
name = "customer details", |
|||
configClazz = TbGetCustomerDetailsNodeConfiguration.class, |
|||
nodeDescription = "Node find the customer of the message originator and fetch his details that selected from the drop-down list and add them to the message if they exist.", |
|||
nodeDetails = "If selected checkbox: <b>Add selected details to the message metadata</b>, existing fields will add to the message metadata instead of message data.<br><br>" + |
|||
"<b>Note:</b> only Device, Asset, and Entity View type are allowed.<br><br>" + |
|||
"If the originator of the message didn't assign to Customer, or originator type is not supported - Message send via <b>Failure</b> chain, otherwise, <b>Success</b> chain will be used.", |
|||
uiResources = {"static/rulenode/rulenode-core-config.js"}, |
|||
configDirective = "tbEnrichmentNodeEntityDetailsConfig") |
|||
public class TbGetCustomerDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetCustomerDetailsNodeConfiguration> { |
|||
|
|||
private static final String CUSTOMER_PREFIX = "customer_"; |
|||
|
|||
@Override |
|||
protected TbGetCustomerDetailsNodeConfiguration loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { |
|||
return TbNodeUtils.convert(configuration, TbGetCustomerDetailsNodeConfiguration.class); |
|||
} |
|||
|
|||
@Override |
|||
protected TbMsg getDetails(TbContext ctx, TbMsg msg) { |
|||
return getCustomerTbMsg(ctx, msg, getDataAsJson(msg)); |
|||
} |
|||
|
|||
private TbMsg getCustomerTbMsg(TbContext ctx, TbMsg msg, MessageData messageData) { |
|||
JsonElement resultObject = null; |
|||
if (!config.getDetailsList().isEmpty()) { |
|||
for (EntityDetails entityDetails : config.getDetailsList()) { |
|||
resultObject = addCustomerProperties(messageData.getData(), getCustomer(ctx, msg), entityDetails); |
|||
} |
|||
return transformMsg(ctx, msg, resultObject, messageData); |
|||
} else { |
|||
return msg; |
|||
} |
|||
} |
|||
|
|||
private Customer 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() + "' didn't assign to Customer."); |
|||
} |
|||
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() + "' didn't assign to Customer."); |
|||
} |
|||
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() + "' didn't assign to Customer."); |
|||
} |
|||
default: |
|||
throw new RuntimeException("Entity with entityType '" + msg.getOriginator().getEntityType() + "' can't be assigned to Customer."); |
|||
} |
|||
} |
|||
|
|||
private JsonElement addCustomerProperties(JsonElement data, Customer customer, EntityDetails entityDetails) { |
|||
JsonObject dataAsObject = data.getAsJsonObject(); |
|||
switch (entityDetails) { |
|||
case ADDRESS: |
|||
if (customer.getAddress() != null) |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "address", customer.getAddress()); |
|||
break; |
|||
case ADDRESS2: |
|||
if (customer.getAddress2() != null) |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "address2", customer.getAddress2()); |
|||
break; |
|||
case CITY: |
|||
if (customer.getCity() != null) dataAsObject.addProperty(CUSTOMER_PREFIX + "city", customer.getCity()); |
|||
break; |
|||
case COUNTRY: |
|||
if (customer.getCountry() != null) |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "country", customer.getCountry()); |
|||
break; |
|||
case STATE: |
|||
if (customer.getState() != null) |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "state", customer.getState()); |
|||
break; |
|||
case EMAIL: |
|||
if (customer.getEmail() != null) |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "email", customer.getEmail()); |
|||
break; |
|||
case PHONE: |
|||
if (customer.getPhone() != null) |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "phone", customer.getPhone()); |
|||
break; |
|||
case ZIP: |
|||
if (customer.getZip() != null) dataAsObject.addProperty(CUSTOMER_PREFIX + "zip", customer.getZip()); |
|||
break; |
|||
case ADDITIONAL_INFO: |
|||
if (customer.getAdditionalInfo().hasNonNull("description")) { |
|||
dataAsObject.addProperty(CUSTOMER_PREFIX + "additionalInfo", customer.getAdditionalInfo().get("description").asText()); |
|||
} |
|||
break; |
|||
} |
|||
return dataAsObject; |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.metadata; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.rule.engine.api.NodeConfiguration; |
|||
|
|||
import java.util.Collections; |
|||
|
|||
@Data |
|||
public class TbGetCustomerDetailsNodeConfiguration extends TbAbstractGetEntityDetailsNodeConfiguration implements NodeConfiguration<TbGetCustomerDetailsNodeConfiguration> { |
|||
|
|||
|
|||
@Override |
|||
public TbGetCustomerDetailsNodeConfiguration defaultConfiguration() { |
|||
TbGetCustomerDetailsNodeConfiguration configuration = new TbGetCustomerDetailsNodeConfiguration(); |
|||
configuration.setDetailsList(Collections.emptyList()); |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,105 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.metadata; |
|||
|
|||
import com.google.gson.JsonElement; |
|||
import com.google.gson.JsonObject; |
|||
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.Tenant; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
|
|||
@Slf4j |
|||
@RuleNode(type = ComponentType.ENRICHMENT, |
|||
name = "tenant details", |
|||
configClazz = TbGetTenantDetailsNodeConfiguration.class, |
|||
nodeDescription = "Node fetch current Tenant details that selected from the drop-down list and add them to the message if they exist.", |
|||
nodeDetails = "If selected checkbox: <b>Add selected details to the message metadata</b>, existing fields will add to the message metadata instead of message data.", |
|||
uiResources = {"static/rulenode/rulenode-core-config.js"}, |
|||
configDirective = "tbEnrichmentNodeEntityDetailsConfig") |
|||
public class TbGetTenantDetailsNode extends TbAbstractGetEntityDetailsNode<TbGetTenantDetailsNodeConfiguration> { |
|||
|
|||
|
|||
private static final String TENANT_PREFIX = "tenant_"; |
|||
|
|||
@Override |
|||
protected TbGetTenantDetailsNodeConfiguration loadGetEntityDetailsNodeConfiguration(TbNodeConfiguration configuration) throws TbNodeException { |
|||
return TbNodeUtils.convert(configuration, TbGetTenantDetailsNodeConfiguration.class); |
|||
} |
|||
|
|||
@Override |
|||
protected TbMsg getDetails(TbContext ctx, TbMsg msg) { |
|||
return getTenantTbMsg(ctx, msg, getDataAsJson(msg)); |
|||
} |
|||
|
|||
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 = addTenantProperties(messageData.getData(), tenant, entityDetails); |
|||
} |
|||
return transformMsg(ctx, msg, resultObject, messageData); |
|||
} else { |
|||
return msg; |
|||
} |
|||
} |
|||
|
|||
private JsonElement addTenantProperties(JsonElement data, Tenant tenant, EntityDetails entityDetails) { |
|||
JsonObject dataAsObject = data.getAsJsonObject(); |
|||
switch (entityDetails) { |
|||
case ADDRESS: |
|||
if (tenant.getAddress() != null) |
|||
dataAsObject.addProperty(TENANT_PREFIX + "address", tenant.getAddress()); |
|||
break; |
|||
case ADDRESS2: |
|||
if (tenant.getAddress2() != null) |
|||
dataAsObject.addProperty(TENANT_PREFIX + "address2", tenant.getAddress2()); |
|||
break; |
|||
case CITY: |
|||
if (tenant.getCity() != null) dataAsObject.addProperty(TENANT_PREFIX + "city", tenant.getCity()); |
|||
break; |
|||
case COUNTRY: |
|||
if (tenant.getCountry() != null) |
|||
dataAsObject.addProperty(TENANT_PREFIX + "country", tenant.getCountry()); |
|||
break; |
|||
case STATE: |
|||
if (tenant.getState() != null) dataAsObject.addProperty(TENANT_PREFIX + "state", tenant.getState()); |
|||
break; |
|||
case EMAIL: |
|||
if (tenant.getEmail() != null) dataAsObject.addProperty(TENANT_PREFIX + "email", tenant.getEmail()); |
|||
break; |
|||
case PHONE: |
|||
if (tenant.getPhone() != null) dataAsObject.addProperty(TENANT_PREFIX + "phone", tenant.getPhone()); |
|||
break; |
|||
case ZIP: |
|||
if (tenant.getZip() != null) dataAsObject.addProperty(TENANT_PREFIX + "zip", tenant.getZip()); |
|||
break; |
|||
case ADDITIONAL_INFO: |
|||
if (tenant.getAdditionalInfo().hasNonNull("description")) { |
|||
dataAsObject.addProperty(TENANT_PREFIX + "additionalInfo", tenant.getAdditionalInfo().get("description").asText()); |
|||
} |
|||
break; |
|||
} |
|||
return dataAsObject; |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.metadata; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.rule.engine.api.NodeConfiguration; |
|||
|
|||
import java.util.Collections; |
|||
|
|||
@Data |
|||
public class TbGetTenantDetailsNodeConfiguration extends TbAbstractGetEntityDetailsNodeConfiguration implements NodeConfiguration<TbGetTenantDetailsNodeConfiguration> { |
|||
|
|||
|
|||
@Override |
|||
public TbGetTenantDetailsNodeConfiguration defaultConfiguration() { |
|||
TbGetTenantDetailsNodeConfiguration configuration = new TbGetTenantDetailsNodeConfiguration(); |
|||
configuration.setDetailsList(Collections.emptyList()); |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
/** |
|||
* Copyright © 2016-2019 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.util; |
|||
|
|||
public enum EntityDetails { |
|||
|
|||
COUNTRY, CITY, STATE, ZIP, ADDRESS, ADDRESS2, PHONE, EMAIL, ADDITIONAL_INFO |
|||
|
|||
} |
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue