Browse Source

Originator Type Switch Node. New Entity lifecycle message types.

pull/804/head
Igor Kulikov 9 years ago
parent
commit
9995f8392c
  1. 12
      application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
  2. 148
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  3. 51
      application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
  4. 8
      common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java
  5. 18
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java
  6. 85
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java
  7. 4
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

12
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java

@ -92,7 +92,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
if (ruleNode.isDebugMode()) {
systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), "Self");
}
tbNode.onMsg(defaultCtx, msg.getMsg());
try {
tbNode.onMsg(defaultCtx, msg.getMsg());
} catch (Exception e) {
defaultCtx.tellFailure(msg.getMsg(), e);
}
}
void onRuleChainToRuleNodeMsg(RuleChainToRuleNodeMsg msg) throws Exception {
@ -100,7 +104,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
if (ruleNode.isDebugMode()) {
systemContext.persistDebugInput(tenantId, entityId, msg.getMsg(), msg.getFromRelationType());
}
tbNode.onMsg(msg.getCtx(), msg.getMsg());
try {
tbNode.onMsg(msg.getCtx(), msg.getMsg());
} catch (Exception e) {
msg.getCtx().tellFailure(msg.getMsg(), e);
}
}
private TbNode initComponent(RuleNode ruleNode) throws Exception {

148
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -15,6 +15,10 @@
*/
package org.thingsboard.server.controller;
import com.datastax.driver.core.utils.UUIDs;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -22,14 +26,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.thingsboard.server.actors.service.ActorService;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.*;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmId;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
@ -37,18 +34,9 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.id.WidgetTypeId;
import org.thingsboard.server.common.data.id.WidgetsBundleId;
import org.thingsboard.server.common.data.id.*;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
@ -57,6 +45,10 @@ import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.audit.AuditLogService;
@ -94,6 +86,8 @@ public abstract class BaseController {
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!";
private static final ObjectMapper json = new ObjectMapper();
@Autowired
private ThingsboardErrorResponseHandler errorResponseHandler;
@ -542,15 +536,127 @@ public abstract class BaseController {
protected <E extends BaseData<I> & HasName,
I extends UUIDBased & EntityId> void logEntityAction(I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException {
User user = getCurrentUser();
logEntityAction(getCurrentUser(), entityId, entity, customerId, actionType, e, additionalInfo);
}
protected <E extends BaseData<I> & HasName,
I extends UUIDBased & EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId,
ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException {
if (customerId == null || customerId.isNullUid()) {
customerId = user.getCustomerId();
}
if (e == null) {
pushEntityActionToRuleEngine(entityId, entity, user, customerId, actionType, additionalInfo);
}
auditLogService.logEntityAction(user.getTenantId(), customerId, user.getId(), user.getName(), entityId, entity, actionType, e, additionalInfo);
}
public static Exception toException(Throwable error) {
return error != null ? (Exception.class.isInstance(error) ? (Exception) error : new Exception(error)) : null;
}
private <E extends BaseData<I> & HasName,
I extends UUIDBased & EntityId> void pushEntityActionToRuleEngine(I entityId, E entity, User user, CustomerId customerId,
ActionType actionType, Object... additionalInfo) {
String msgType = null;
switch (actionType) {
case ADDED:
msgType = DataConstants.ENTITY_CREATED;
break;
case DELETED:
msgType = DataConstants.ENTITY_DELETED;
break;
case UPDATED:
msgType = DataConstants.ENTITY_UPDATED;
break;
case ASSIGNED_TO_CUSTOMER:
msgType = DataConstants.ENTITY_ASSIGNED;
break;
case UNASSIGNED_FROM_CUSTOMER:
msgType = DataConstants.ENTITY_UNASSIGNED;
break;
case ATTRIBUTES_UPDATED:
msgType = DataConstants.ATTRIBUTES_UPDATED;
break;
case ATTRIBUTES_DELETED:
msgType = DataConstants.ATTRIBUTES_DELETED;
break;
}
if (!StringUtils.isEmpty(msgType)) {
try {
TbMsgMetaData metaData = new TbMsgMetaData();
metaData.putValue("userId", user.getId().toString());
metaData.putValue("userName", user.getName());
if (customerId != null && !customerId.isNullUid()) {
metaData.putValue("customerId", customerId.toString());
}
if (actionType == ActionType.ASSIGNED_TO_CUSTOMER) {
String strCustomerId = extractParameter(String.class, 1, additionalInfo);
String strCustomerName = extractParameter(String.class, 2, additionalInfo);
metaData.putValue("assignedCustomerId", strCustomerId);
metaData.putValue("assignedCustomerName", strCustomerName);
} else if (actionType == ActionType.UNASSIGNED_FROM_CUSTOMER) {
String strCustomerId = extractParameter(String.class, 1, additionalInfo);
String strCustomerName = extractParameter(String.class, 2, additionalInfo);
metaData.putValue("unassignedCustomerId", strCustomerId);
metaData.putValue("unassignedCustomerName", strCustomerName);
}
ObjectNode entityNode;
if (entity != null) {
entityNode = json.valueToTree(entity);
if (entityId.getEntityType() == EntityType.DASHBOARD) {
entityNode.put("configuration", "");
}
} else {
entityNode = json.createObjectNode();
if (actionType == ActionType.ATTRIBUTES_UPDATED) {
String scope = extractParameter(String.class, 0, additionalInfo);
List<AttributeKvEntry> attributes = extractParameter(List.class, 1, additionalInfo);
metaData.putValue("scope", scope);
if (attributes != null) {
for (AttributeKvEntry attr : attributes) {
if (attr.getDataType() == DataType.BOOLEAN) {
entityNode.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE) {
entityNode.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG) {
entityNode.put(attr.getKey(), attr.getLongValue().get());
} else {
entityNode.put(attr.getKey(), attr.getValueAsString());
}
}
}
} else if (actionType == ActionType.ATTRIBUTES_DELETED) {
String scope = extractParameter(String.class, 0, additionalInfo);
List<String> keys = extractParameter(List.class, 1, additionalInfo);
metaData.putValue("scope", scope);
ArrayNode attrsArrayNode = entityNode.putArray("attributes");
if (keys != null) {
keys.forEach(attrsArrayNode::add);
}
}
}
TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), msgType, entityId, metaData, TbMsgDataType.JSON
, json.writeValueAsString(entityNode)
, null, null, 0L);
actorService.onMsg(new ServiceToRuleEngineMsg(user.getTenantId(), tbMsg));
} catch (Exception e) {
log.warn("[{}] Failed to push entity action to rule engine: {}", entityId, actionType, e);
}
}
}
private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) {
T result = null;
if (additionalInfo != null && additionalInfo.length > index) {
Object paramObject = additionalInfo[index];
if (clazz.isInstance(paramObject)) {
result = clazz.cast(paramObject);
}
}
return result;
}
}

51
application/src/main/java/org/thingsboard/server/controller/TelemetryController.java

@ -493,46 +493,31 @@ public class TelemetryController extends BaseController {
}
private void logAttributesDeleted(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
auditLogService.logEntityAction(
user.getTenantId(),
user.getCustomerId(),
user.getId(),
user.getName(),
(UUIDBased & EntityId) entityId,
null,
ActionType.ATTRIBUTES_DELETED,
toException(e),
scope,
keys);
try {
logEntityAction(user, (UUIDBased & EntityId)entityId, null, null, ActionType.ATTRIBUTES_DELETED, toException(e),
scope, keys);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes delete", te);
}
}
private void logAttributesUpdated(SecurityUser user, EntityId entityId, String scope, List<AttributeKvEntry> attributes, Throwable e) {
auditLogService.logEntityAction(
user.getTenantId(),
user.getCustomerId(),
user.getId(),
user.getName(),
(UUIDBased & EntityId) entityId,
null,
ActionType.ATTRIBUTES_UPDATED,
toException(e),
scope,
attributes);
try {
logEntityAction(user, (UUIDBased & EntityId)entityId, null, null, ActionType.ATTRIBUTES_UPDATED, toException(e),
scope, attributes);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes update", te);
}
}
private void logAttributesRead(SecurityUser user, EntityId entityId, String scope, List<String> keys, Throwable e) {
auditLogService.logEntityAction(
user.getTenantId(),
user.getCustomerId(),
user.getId(),
user.getName(),
(UUIDBased & EntityId) entityId,
null,
ActionType.ATTRIBUTES_READ,
toException(e),
scope,
keys);
try {
logEntityAction(user, (UUIDBased & EntityId)entityId, null, null, ActionType.ATTRIBUTES_READ, toException(e),
scope, keys);
} catch (ThingsboardException te) {
log.warn("Failed to log attributes read", te);
}
}
private ListenableFuture<List<AttributeKvEntry>> mergeAllAttributesFutures(List<ListenableFuture<List<AttributeKvEntry>>> futures) {

8
common/data/src/main/java/org/thingsboard/server/common/data/DataConstants.java

@ -50,4 +50,12 @@ public class DataConstants {
public static final String DISCONNECT_EVENT = "DISCONNECT_EVENT";
public static final String ACTIVITY_EVENT = "ACTIVITY_EVENT";
public static final String ENTITY_CREATED = "ENTITY_CREATED";
public static final String ENTITY_UPDATED = "ENTITY_UPDATED";
public static final String ENTITY_DELETED = "ENTITY_DELETED";
public static final String ENTITY_ASSIGNED = "ENTITY_ASSIGNED";
public static final String ENTITY_UNASSIGNED = "ENTITY_UNASSIGNED";
public static final String ATTRIBUTES_UPDATED = "ATTRIBUTES_UPDATED";
public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED";
}

18
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbMsgTypeSwitchNode.java

@ -28,7 +28,9 @@ import org.thingsboard.server.common.msg.session.SessionMsgType;
type = ComponentType.FILTER,
name = "message type switch",
configClazz = EmptyNodeConfiguration.class,
relationTypes = {"Post attributes", "Post telemetry", "RPC Request", "Activity Event", "Inactivity Event", "Connect Event", "Disconnect Event", "Other"},
relationTypes = {"Post attributes", "Post telemetry", "RPC Request", "Activity Event", "Inactivity Event",
"Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned",
"Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Other"},
nodeDescription = "Route incoming messages by Message Type",
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
@ -59,6 +61,20 @@ public class TbMsgTypeSwitchNode implements TbNode {
relationType = "Connect Event";
} else if (msg.getType().equals(DataConstants.DISCONNECT_EVENT)) {
relationType = "Disconnect Event";
} else if (msg.getType().equals(DataConstants.ENTITY_CREATED)) {
relationType = "Entity Created";
} else if (msg.getType().equals(DataConstants.ENTITY_UPDATED)) {
relationType = "Entity Updated";
} else if (msg.getType().equals(DataConstants.ENTITY_DELETED)) {
relationType = "Entity Deleted";
} else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED)) {
relationType = "Entity Assigned";
} else if (msg.getType().equals(DataConstants.ENTITY_UNASSIGNED)) {
relationType = "Entity Unassigned";
} else if (msg.getType().equals(DataConstants.ATTRIBUTES_UPDATED)) {
relationType = "Attributes Updated";
} else if (msg.getType().equals(DataConstants.ATTRIBUTES_DELETED)) {
relationType = "Attributes Deleted";
} else {
relationType = "Other";
}

85
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/filter/TbOriginatorTypeSwitchNode.java

@ -0,0 +1,85 @@
/**
* Copyright © 2016-2018 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.filter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.TbNodeUtils;
import org.thingsboard.rule.engine.api.*;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "originator type switch",
configClazz = EmptyNodeConfiguration.class,
relationTypes = {"Device", "Asset", "Tenant", "Customer", "User", "Dashboard", "Rule chain", "Rule node"},
nodeDescription = "Route incoming messages by Message Originator Type",
nodeDetails = "Routes messages to chain according to the originator type ('Device', 'Asset', etc.).",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig")
public class TbOriginatorTypeSwitchNode implements TbNode {
EmptyNodeConfiguration config;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, EmptyNodeConfiguration.class);
}
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws TbNodeException {
String relationType;
EntityType originatorType = msg.getOriginator().getEntityType();
switch (originatorType) {
case TENANT:
relationType = "Tenant";
break;
case CUSTOMER:
relationType = "Customer";
break;
case USER:
relationType = "User";
break;
case DASHBOARD:
relationType = "Dashboard";
break;
case ASSET:
relationType = "Asset";
break;
case DEVICE:
relationType = "Device";
break;
case RULE_CHAIN:
relationType = "Rule chain";
break;
case RULE_NODE:
relationType = "Rule node";
break;
default:
throw new TbNodeException("Unsupported originator type: " + originatorType);
}
ctx.tellNext(msg, relationType);
}
@Override
public void destroy() {
}
}

4
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save