Rule Chain Controller description

This commit is contained in:
Andrii Shvaika 2021-10-19 15:15:39 +03:00
parent b0912519e4
commit 546bded363
10 changed files with 185 additions and 17 deletions

View File

@ -187,11 +187,13 @@ public abstract class BaseController {
protected static final String DEVICE_TYPE_DESCRIPTION = "Device type as the name of the device profile"; protected static final String DEVICE_TYPE_DESCRIPTION = "Device type as the name of the device profile";
protected static final String ASSET_TYPE_DESCRIPTION = "Asset type"; protected static final String ASSET_TYPE_DESCRIPTION = "Asset type";
protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'"; protected static final String EDGE_TYPE_DESCRIPTION = "A string value representing the edge type. For example, 'default'";
protected static final String RULE_CHAIN_TYPE_DESCRIPTION = "Rule chain type (CORE or EDGE)";
protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name."; protected static final String ASSET_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the asset name.";
protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title."; protected static final String DASHBOARD_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the dashboard title.";
protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty."; protected static final String RPC_TEXT_SEARCH_DESCRIPTION = "Not implemented. Leave empty.";
protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name."; protected static final String DEVICE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device name.";
protected static final String RULE_CHAIN_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the rule chain name.";
protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name."; protected static final String DEVICE_PROFILE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the device profile name.";
protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title."; protected static final String CUSTOMER_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the customer title.";
protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name."; protected static final String EDGE_TEXT_SEARCH_DESCRIPTION = "The case insensitive 'startsWith' filter based on the edge name.";
@ -207,10 +209,12 @@ public abstract class BaseController {
protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status"; protected static final String ALARM_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, startTs, endTs, type, ackTs, clearTs, severity, status";
protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id"; protected static final String EVENT_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, id";
protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle"; protected static final String EDGE_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, type, label, customerTitle";
protected static final String RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, name, root";
protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus"; protected static final String AUDIT_LOG_SORT_PROPERTY_ALLOWABLE_VALUES = "createdTime, entityType, entityName, userName, actionType, actionStatus";
protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)"; protected static final String SORT_ORDER_DESCRIPTION = "Sort order. ASC (ASCENDING) or DESC (DESCENDING)";
protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC"; protected static final String SORT_ORDER_ALLOWABLE_VALUES = "ASC, DESC";
protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED"; protected static final String RPC_STATUS_ALLOWABLE_VALUES = "QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED";
protected static final String RULE_CHAIN_TYPES_ALLOWABLE_VALUES = "CORE, EDGE";
protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP"; protected static final String TRANSPORT_TYPE_ALLOWABLE_VALUES = "DEFAULT, MQTT, COAP, LWM2M, SNMP";
protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. "; protected static final String DEVICE_INFO_DESCRIPTION = "Device Info is an extension of the default Device object that contains information about the assigned customer name and device profile name. ";
protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. "; protected static final String ASSET_INFO_DESCRIPTION = "Asset Info is an extension of the default Asset object that contains information about the assigned customer name. ";

View File

@ -91,9 +91,9 @@ public class RpcV2Controller extends AbstractRpcController {
"In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " + "In case of persistent RPC, the result of this call is 'rpcId' UUID. In case of lightweight RPC, " +
"the result of this call is the response from device, or 504 Gateway Timeout if device is offline."; "the result of this call is the response from device, or 504 Gateway Timeout if device is offline.";
private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT; private static final String ONE_WAY_RPC_REQUEST_DESCRIPTION = "Sends the one-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + ONE_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH;
private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT; private static final String TWO_WAY_RPC_REQUEST_DESCRIPTION = "Sends the two-way remote-procedure call (RPC) request to device. " + RPC_REQUEST_DESCRIPTION + TWO_WAY_RPC_RESULT + TENANT_AND_USER_AUTHORITY_PARAGRAPH;
@ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION) @ApiOperation(value = "Send one-way RPC request", notes = ONE_WAY_RPC_REQUEST_DESCRIPTION)
@ApiResponses(value = { @ApiResponses(value = {
@ -131,7 +131,7 @@ public class RpcV2Controller extends AbstractRpcController {
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT); return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody, HttpStatus.GATEWAY_TIMEOUT, HttpStatus.GATEWAY_TIMEOUT);
} }
@ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call.") @ApiOperation(value = "Get persistent RPC request", notes = "Get information about the status of the RPC call." + TENANT_AND_USER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET) @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -147,7 +147,7 @@ public class RpcV2Controller extends AbstractRpcController {
} }
} }
@ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination.") @ApiOperation(value = "Get persistent RPC requests", notes = "Allows to query RPC calls for specific device using pagination." + TENANT_AND_USER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET) @RequestMapping(value = "/persistent/device/{deviceId}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -177,7 +177,7 @@ public class RpcV2Controller extends AbstractRpcController {
} }
} }
@ApiOperation(value = "Delete persistent RPC", notes = "Deletes the persistent RPC request.") @ApiOperation(value = "Delete persistent RPC", notes = "Deletes the persistent RPC request." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE) @RequestMapping(value = "/persistent/{rpcId}", method = RequestMethod.DELETE)
@ResponseBody @ResponseBody

View File

@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@ -95,6 +96,25 @@ public class RuleChainController extends BaseController {
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectMapper objectMapper = new ObjectMapper();
public static final int TIMEOUT = 20; public static final int TIMEOUT = 20;
private static final String RULE_CHAIN_DESCRIPTION = "The rule chain object is lightweight and contains general information about the rule chain. " +
"List of rule nodes and their connection is stored in a separate 'metadata' object.";
private static final String RULE_CHAIN_METADATA_DESCRIPTION = "The metadata object contains information about the rule nodes and their connections.";
private static final String TEST_JS_FUNCTION = "Execute the JavaScript function and return the result. The format of request: \n\n"
+ MARKDOWN_CODE_BLOCK_START
+ "{\n" +
" \"script\": \"Your JS Function as String\",\n" +
" \"scriptType\": \"One of: update, generate, filter, switch, json, string\",\n" +
" \"argNames\": [\"msg\", \"metadata\", \"type\"],\n" +
" \"msg\": \"{\\\"temperature\\\": 42}\", \n" +
" \"metadata\": {\n" +
" \"deviceName\": \"Device A\",\n" +
" \"deviceType\": \"Thermometer\"\n" +
" },\n" +
" \"msgType\": \"POST_TELEMETRY_REQUEST\"\n" +
"}"
+ MARKDOWN_CODE_BLOCK_END
+ "\n\n Expected result JSON contains \"output\" and \"error\".";
@Autowired @Autowired
private InstallScripts installScripts; private InstallScripts installScripts;
@ -110,10 +130,14 @@ public class RuleChainController extends BaseController {
@Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}") @Value("${actors.rule.chain.debug_mode_rate_limits_per_tenant.enabled}")
private boolean debugPerTenantEnabled; private boolean debugPerTenantEnabled;
@ApiOperation(value = "Get Rule Chain (getRuleChainById)",
notes = "Fetch the Rule Chain object based on the provided Rule Chain Id. " + RULE_CHAIN_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET) @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public RuleChain getRuleChainById(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { public RuleChain getRuleChainById(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId); checkParameter(RULE_CHAIN_ID, strRuleChainId);
try { try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -123,10 +147,14 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Get Rule Chain (getRuleChainById)",
notes = "Fetch the Rule Chain Metadata object based on the provided Rule Chain Id. " + RULE_CHAIN_METADATA_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET) @RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public RuleChainMetaData getRuleChainMetaData(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { public RuleChainMetaData getRuleChainMetaData(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId); checkParameter(RULE_CHAIN_ID, strRuleChainId);
try { try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -137,11 +165,18 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Create Or Update Rule Chain (saveRuleChain)",
notes = "Create or update the Rule Chain. When creating Rule Chain, platform generates Rule Chain Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address). " +
"The newly created Rule Chain Id will be present in the response. " +
"Specify existing Rule Chain id to update the rule chain. " +
"Referencing non-existing rule chain Id will cause 'Not Found' error." +
"\n\n" + RULE_CHAIN_DESCRIPTION)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST) @RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public RuleChain saveRuleChain(@RequestBody RuleChain ruleChain) throws ThingsboardException { public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the rule chain.")
@RequestBody RuleChain ruleChain) throws ThingsboardException {
try { try {
boolean created = ruleChain.getId() == null; boolean created = ruleChain.getId() == null;
ruleChain.setTenantId(getCurrentUser().getTenantId()); ruleChain.setTenantId(getCurrentUser().getTenantId());
@ -175,10 +210,15 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Create Default Rule Chain",
notes = "Create rule chain from template, based on the specified name in the request. " +
"Creates the rule chain based on the template that is used to create root rule chain. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/device/default", method = RequestMethod.POST) @RequestMapping(value = "/ruleChain/device/default", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public RuleChain saveRuleChain(@RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException { public RuleChain saveRuleChain(
@ApiParam(value = "A JSON value representing the request.")
@RequestBody DefaultRuleChainCreateRequest request) throws ThingsboardException {
try { try {
checkNotNull(request); checkNotNull(request);
checkParameter(request.getName(), "name"); checkParameter(request.getName(), "name");
@ -198,10 +238,14 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Set Root Rule Chain (setRootRuleChain)",
notes = "Makes the rule chain to be root rule chain. Updates previous root rule chain as well. " + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST) @RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public RuleChain setRootRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { public RuleChain setRootRuleChain(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId); checkParameter(RULE_CHAIN_ID, strRuleChainId);
try { try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -237,10 +281,14 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Update Rule Chain Metadata",
notes = "Updates the rule chain metadata. " + RULE_CHAIN_METADATA_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST) @RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException { public RuleChainMetaData saveRuleChainMetaData(
@ApiParam(value = "A JSON value representing the rule chain metadata.")
@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException {
try { try {
TenantId tenantId = getTenantId(); TenantId tenantId = getTenantId();
if (debugPerTenantEnabled) { if (debugPerTenantEnabled) {
@ -278,15 +326,24 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Get Rule Chains (getRuleChains)",
notes = "Returns a page of Rule Chains owned by tenant. " + RULE_CHAIN_DESCRIPTION + PAGE_DATA_PARAMETERS)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET) @RequestMapping(value = "/ruleChains", params = {"pageSize", "page"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public PageData<RuleChain> getRuleChains( public PageData<RuleChain> getRuleChains(
@ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true)
@RequestParam int pageSize, @RequestParam int pageSize,
@ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true)
@RequestParam int page, @RequestParam int page,
@ApiParam(value = RULE_CHAIN_TYPE_DESCRIPTION, allowableValues = RULE_CHAIN_TYPES_ALLOWABLE_VALUES)
@RequestParam(value = "type", required = false) String typeStr, @RequestParam(value = "type", required = false) String typeStr,
@ApiParam(value = RULE_CHAIN_TEXT_SEARCH_DESCRIPTION)
@RequestParam(required = false) String textSearch, @RequestParam(required = false) String textSearch,
@ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = RULE_CHAIN_SORT_PROPERTY_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortProperty, @RequestParam(required = false) String sortProperty,
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder) throws ThingsboardException { @RequestParam(required = false) String sortOrder) throws ThingsboardException {
try { try {
TenantId tenantId = getCurrentUser().getTenantId(); TenantId tenantId = getCurrentUser().getTenantId();
@ -301,10 +358,14 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Delete rule chain (deleteRuleChain)",
notes = "Deletes the rule chain. Referencing non-existing rule chain Id will cause an error. Referencing rule chain that is used in the device profiles will cause an error.")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE) @RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK) @ResponseStatus(value = HttpStatus.OK)
public void deleteRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException { public void deleteRuleChain(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId); checkParameter(RULE_CHAIN_ID, strRuleChainId);
try { try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId)); RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
@ -347,10 +408,15 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Get latest input message (getLatestRuleNodeDebugInput)",
notes = "Gets the input message from the debug events for specified Rule Chain Id. " +
"Referencing non-existing rule chain Id will cause an error. ")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET) @RequestMapping(value = "/ruleNode/{ruleNodeId}/debugIn", method = RequestMethod.GET)
@ResponseBody @ResponseBody
public JsonNode getLatestRuleNodeDebugInput(@PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException { public JsonNode getLatestRuleNodeDebugInput(
@ApiParam(value = RULE_CHAIN_ID_PARAM_DESCRIPTION)
@PathVariable(RULE_NODE_ID) String strRuleNodeId) throws ThingsboardException {
checkParameter(RULE_NODE_ID, strRuleNodeId); checkParameter(RULE_NODE_ID, strRuleNodeId);
try { try {
RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId)); RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId));
@ -373,10 +439,15 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Test JavaScript function",
notes = TEST_JS_FUNCTION + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST) @RequestMapping(value = "/ruleChain/testScript", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public JsonNode testScript(@RequestBody JsonNode inputParams) throws ThingsboardException { public JsonNode testScript(
@ApiParam(value = "Test JS request. See API call description above.")
@RequestBody JsonNode inputParams) throws ThingsboardException {
try { try {
String script = inputParams.get("script").asText(); String script = inputParams.get("script").asText();
String scriptType = inputParams.get("scriptType").asText(); String scriptType = inputParams.get("scriptType").asText();
@ -436,10 +507,13 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Export Rule Chains", notes = "Exports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChains/export", params = {"limit"}, method = RequestMethod.GET) @RequestMapping(value = "/ruleChains/export", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody @ResponseBody
public RuleChainData exportRuleChains(@RequestParam("limit") int limit) throws ThingsboardException { public RuleChainData exportRuleChains(
@ApiParam(value = "A limit of rule chains to export.", required = true)
@RequestParam("limit") int limit) throws ThingsboardException {
try { try {
TenantId tenantId = getCurrentUser().getTenantId(); TenantId tenantId = getCurrentUser().getTenantId();
PageLink pageLink = new PageLink(limit); PageLink pageLink = new PageLink(limit);
@ -449,10 +523,15 @@ public class RuleChainController extends BaseController {
} }
} }
@ApiOperation(value = "Import Rule Chains", notes = "Imports all tenant rule chains as one JSON." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')") @PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST) @RequestMapping(value = "/ruleChains/import", method = RequestMethod.POST)
@ResponseBody @ResponseBody
public void importRuleChains(@RequestBody RuleChainData ruleChainData, @RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException { public void importRuleChains(
@ApiParam(value = "A JSON value representing the rule chains.")
@RequestBody RuleChainData ruleChainData,
@ApiParam(value = "Enables overwrite for existing rule chains with the same name.")
@RequestParam(required = false, defaultValue = "false") boolean overwrite) throws ThingsboardException {
try { try {
TenantId tenantId = getCurrentUser().getTenantId(); TenantId tenantId = getCurrentUser().getTenantId();
List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite); List<RuleChainImportResult> importResults = ruleChainService.importTenantRuleChains(tenantId, ruleChainData, RuleChainType.CORE, overwrite);

View File

@ -15,17 +15,21 @@
*/ */
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.io.Serializable; import java.io.Serializable;
@ApiModel
@Data @Data
@Slf4j @Slf4j
public class DefaultRuleChainCreateRequest implements Serializable { public class DefaultRuleChainCreateRequest implements Serializable {
private static final long serialVersionUID = 5600333716030561537L; private static final long serialVersionUID = 5600333716030561537L;
@ApiModelProperty(position = 1, required = true, value = "Name of the new rule chain", example = "Root Rule Chain")
private String name; private String name;
} }

View File

@ -15,14 +15,20 @@
*/ */
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
/** /**
* Created by ashvayka on 21.03.18. * Created by ashvayka on 21.03.18.
*/ */
@ApiModel
@Data @Data
public class NodeConnectionInfo { public class NodeConnectionInfo {
@ApiModelProperty(position = 1, required = true, value = "Index of rule node in the 'nodes' array of the RuleChainMetaData. Indicates the 'from' part of the connection.")
private int fromIndex; private int fromIndex;
@ApiModelProperty(position = 2, required = true, value = "Index of rule node in the 'nodes' array of the RuleChainMetaData. Indicates the 'to' part of the connection.")
private int toIndex; private int toIndex;
@ApiModelProperty(position = 3, required = true, value = "Type of the relation. Typically indicated the result of processing by the 'from' rule node. For example, 'Success' or 'Failure'")
private String type; private String type;
} }

View File

@ -17,6 +17,8 @@ package org.thingsboard.server.common.data.rule;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -28,6 +30,7 @@ import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.NoXss; import org.thingsboard.server.common.data.validation.NoXss;
@ApiModel
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Slf4j @Slf4j
@ -35,13 +38,20 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im
private static final long serialVersionUID = -5656679015121935465L; private static final long serialVersionUID = -5656679015121935465L;
@ApiModelProperty(position = 3, required = true, value = "JSON object with Tenant Id.", readOnly = true)
private TenantId tenantId; private TenantId tenantId;
@NoXss @NoXss
@ApiModelProperty(position = 4, required = true, value = "Rule Chain name", example = "Humidity data processing")
private String name; private String name;
@ApiModelProperty(position = 5, value = "Rule Chain type. 'EDGE' rule chains are processing messages on the edge devices only.", example = "A4B72CCDFF33")
private RuleChainType type; private RuleChainType type;
@ApiModelProperty(position = 6, value = "JSON object with Rule Chain Id. Pointer to the first rule node that should receive all messages pushed to this rule chain.")
private RuleNodeId firstRuleNodeId; private RuleNodeId firstRuleNodeId;
@ApiModelProperty(position = 7, value = "Indicates root rule chain. The root rule chain process messages from all devices and entities by default. User may configure default rule chain per device profile.")
private boolean root; private boolean root;
@ApiModelProperty(position = 8, value = "Reserved for future usage.")
private boolean debugMode; private boolean debugMode;
@ApiModelProperty(position = 9, value = "Reserved for future usage. The actual list of rule nodes and their relations is stored in the database separately.")
private transient JsonNode configuration; private transient JsonNode configuration;
@JsonIgnore @JsonIgnore
@ -75,6 +85,21 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im
return name; return name;
} }
@ApiModelProperty(position = 1, value = "JSON object with the Rule Chain Id. " +
"Specify this field to update the Rule Chain. " +
"Referencing non-existing Rule Chain Id will cause error. " +
"Omit this field to create new rule chain." )
@Override
public RuleChainId getId() {
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the rule chain creation, in milliseconds", example = "1609459200000", readOnly = true)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
public JsonNode getConfiguration() { public JsonNode getConfiguration() {
return SearchTextBasedWithAdditionalInfo.getJson(() -> configuration, () -> configurationBytes); return SearchTextBasedWithAdditionalInfo.getJson(() -> configuration, () -> configurationBytes);
} }
@ -82,4 +107,5 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im
public void setConfiguration(JsonNode data) { public void setConfiguration(JsonNode data) {
setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes); setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes);
} }
} }

View File

@ -16,16 +16,23 @@
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
/** /**
* Created by ashvayka on 21.03.18. * Created by ashvayka on 21.03.18.
*/ */
@ApiModel
@Data @Data
public class RuleChainConnectionInfo { public class RuleChainConnectionInfo {
@ApiModelProperty(position = 1, required = true, value = "Index of rule node in the 'nodes' array of the RuleChainMetaData. Indicates the 'from' part of the connection.")
private int fromIndex; private int fromIndex;
@ApiModelProperty(position = 2, required = true, value = "JSON object with the Rule Chain Id.")
private RuleChainId targetRuleChainId; private RuleChainId targetRuleChainId;
@ApiModelProperty(position = 3, required = true, value = "JSON object with the additional information about the connection.")
private JsonNode additionalInfo; private JsonNode additionalInfo;
@ApiModelProperty(position = 4, required = true, value = "Type of the relation. Typically indicated the result of processing by the 'from' rule node. For example, 'Success' or 'Failure'")
private String type; private String type;
} }

View File

@ -15,13 +15,18 @@
*/ */
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@ApiModel
@Data @Data
public class RuleChainData { public class RuleChainData {
@ApiModelProperty(position = 1, required = true, value = "List of the Rule Chain objects.", readOnly = true)
List<RuleChain> ruleChains; List<RuleChain> ruleChains;
@ApiModelProperty(position = 2, required = true, value = "List of the Rule Chain metadata objects.", readOnly = true)
List<RuleChainMetaData> metadata; List<RuleChainMetaData> metadata;
} }

View File

@ -16,6 +16,8 @@
package org.thingsboard.server.common.data.rule; package org.thingsboard.server.common.data.rule;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
@ -25,17 +27,23 @@ import java.util.List;
/** /**
* Created by igor on 3/13/18. * Created by igor on 3/13/18.
*/ */
@ApiModel
@Data @Data
public class RuleChainMetaData { public class RuleChainMetaData {
@ApiModelProperty(position = 1, required = true, value = "JSON object with Rule Chain Id.", readOnly = true)
private RuleChainId ruleChainId; private RuleChainId ruleChainId;
@ApiModelProperty(position = 2, required = true, value = "Index of the first rule node in the 'nodes' list")
private Integer firstNodeIndex; private Integer firstNodeIndex;
@ApiModelProperty(position = 3, required = true, value = "List of rule node JSON objects")
private List<RuleNode> nodes; private List<RuleNode> nodes;
@ApiModelProperty(position = 4, required = true, value = "List of JSON objects that represent connections between rule nodes")
private List<NodeConnectionInfo> connections; private List<NodeConnectionInfo> connections;
@ApiModelProperty(position = 5, required = true, value = "List of JSON objects that represent connections between rule nodes and other rule chains.")
private List<RuleChainConnectionInfo> ruleChainConnections; private List<RuleChainConnectionInfo> ruleChainConnections;
public void addConnectionInfo(int fromIndex, int toIndex, String type) { public void addConnectionInfo(int fromIndex, int toIndex, String type) {

View File

@ -17,6 +17,8 @@ package org.thingsboard.server.common.data.rule;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -25,6 +27,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.RuleNodeId;
@ApiModel
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Slf4j @Slf4j
@ -32,10 +35,15 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
private static final long serialVersionUID = -5656679015121235465L; private static final long serialVersionUID = -5656679015121235465L;
@ApiModelProperty(position = 3, value = "JSON object with the Rule Chain Id. ", readOnly = true)
private RuleChainId ruleChainId; private RuleChainId ruleChainId;
@ApiModelProperty(position = 4, value = "Full Java Class Name of the rule node implementation. ", example = "com.mycompany.iot.rule.engine.ProcessingNode")
private String type; private String type;
@ApiModelProperty(position = 5, value = "User defined name of the rule node. Used on UI and for logging. ", example = "Process sensor reading")
private String name; private String name;
@ApiModelProperty(position = 6, value = "Enable/disable debug. ", example = "false")
private boolean debugMode; private boolean debugMode;
@ApiModelProperty(position = 7, value = "JSON with the rule node configuration. Structure depends on the rule node implementation.", dataType = "com.fasterxml.jackson.databind.JsonNode")
private transient JsonNode configuration; private transient JsonNode configuration;
@JsonIgnore @JsonIgnore
private byte[] configurationBytes; private byte[] configurationBytes;
@ -75,4 +83,25 @@ public class RuleNode extends SearchTextBasedWithAdditionalInfo<RuleNodeId> impl
setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes); setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes);
} }
@ApiModelProperty(position = 1, value = "JSON object with the Rule Node Id. " +
"Specify this field to update the Rule Node. " +
"Referencing non-existing Rule Node Id will cause error. " +
"Omit this field to create new rule node." )
@Override
public RuleNodeId getId() {
return super.getId();
}
@ApiModelProperty(position = 2, value = "Timestamp of the rule node creation, in milliseconds", example = "1609459200000", readOnly = true)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
@ApiModelProperty(position = 8, value = "Additional parameters of the rule node. Contains 'layoutX' and 'layoutY' properties for visualization.", dataType = "com.fasterxml.jackson.databind.JsonNode")
@Override
public JsonNode getAdditionalInfo() {
return super.getAdditionalInfo();
}
} }