Feature/tb get entity details nodes (#1598)
* init commit * add ui-configuration * EntityDetailsNodes
This commit is contained in:
parent
d5d64ae3b8
commit
4ff006640f
@ -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…
x
Reference in New Issue
Block a user