Merge remote-tracking branch 'origin/develop/1.5' into develop/1.5-queue

This commit is contained in:
Andrew Shvayka 2018-04-27 18:49:35 +03:00
commit 7e6a98110e
19 changed files with 321 additions and 99 deletions

View File

@ -12,48 +12,8 @@
"nodes": [
{
"additionalInfo": {
"layoutX": 639,
"layoutY": 113
},
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode",
"name": "PostAttributes",
"debugMode": true,
"configuration": {
"messageTypes": [
"POST_ATTRIBUTES_REQUEST"
]
}
},
{
"additionalInfo": {
"layoutX": 638,
"layoutY": 206
},
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode",
"name": "PostTelemetry",
"debugMode": true,
"configuration": {
"messageTypes": [
"POST_TELEMETRY_REQUEST"
]
}
},
{
"additionalInfo": {
"layoutX": 297,
"layoutY": 148
},
"type": "org.thingsboard.rule.engine.action.TbLogNode",
"name": "Log",
"debugMode": false,
"configuration": {
"jsScript": "return 'incoming message = ' + msg;"
}
},
{
"additionalInfo": {
"layoutX": 905,
"layoutY": 203
"layoutX": 824,
"layoutY": 156
},
"type": "org.thingsboard.rule.engine.telemetry.TbMsgTimeseriesNode",
"name": "SaveTS",
@ -64,8 +24,8 @@
},
{
"additionalInfo": {
"layoutX": 904,
"layoutY": 110
"layoutX": 825,
"layoutY": 52
},
"type": "org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode",
"name": "save client attributes",
@ -73,30 +33,66 @@
"configuration": {
"scope": "CLIENT_SCOPE"
}
},
{
"additionalInfo": {
"layoutX": 347,
"layoutY": 149
},
"type": "org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode",
"name": "Message Type Switch",
"debugMode": false,
"configuration": {
"version": 0
}
},
{
"additionalInfo": {
"layoutX": 825,
"layoutY": 266
},
"type": "org.thingsboard.rule.engine.action.TbLogNode",
"name": "Log RPC",
"debugMode": false,
"configuration": {
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
}
},
{
"additionalInfo": {
"layoutX": 825,
"layoutY": 379
},
"type": "org.thingsboard.rule.engine.action.TbLogNode",
"name": "Log Other",
"debugMode": false,
"configuration": {
"jsScript": "return '\\nIncoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);"
}
}
],
"connections": [
{
"fromIndex": 0,
"toIndex": 4,
"type": "True"
},
{
"fromIndex": 1,
"toIndex": 3,
"type": "True"
},
{
"fromIndex": 2,
"toIndex": 0,
"type": "Success"
"toIndex": 4,
"type": "Other"
},
{
"fromIndex": 2,
"toIndex": 1,
"type": "Success"
"type": "Post attributes"
},
{
"fromIndex": 2,
"toIndex": 0,
"type": "Post telemetry"
},
{
"fromIndex": 2,
"toIndex": 3,
"type": "RPC Request"
}
],
"ruleChainConnections": null
}
}
}

View File

@ -84,6 +84,7 @@ CREATE MATERIALIZED VIEW IF NOT EXISTS thingsboard.rule_chain_by_tenant_and_sear
CREATE TABLE IF NOT EXISTS thingsboard.rule_node (
id uuid,
rule_chain_id uuid,
type text,
name text,
debug_mode boolean,

View File

@ -28,6 +28,7 @@ CREATE TABLE IF NOT EXISTS rule_chain (
CREATE TABLE IF NOT EXISTS rule_node (
id varchar(31) NOT NULL CONSTRAINT rule_node_pkey PRIMARY KEY,
rule_chain_id varchar(31),
additional_info varchar,
configuration varchar(10000000),
type varchar(255),

View File

@ -23,9 +23,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.install.DatabaseSchemaService;
import org.thingsboard.server.service.install.DatabaseUpgradeService;
import org.thingsboard.server.service.install.SystemDataLoaderService;
import org.thingsboard.server.service.install.*;
import java.nio.file.Paths;
@ -40,9 +38,6 @@ public class ThingsboardInstallService {
@Value("${install.upgrade.from_version:1.2.3}")
private String upgradeFromVersion;
@Value("${install.data_dir}")
private String dataDir;
@Value("${install.load_demo:false}")
private Boolean loadDemo;
@ -61,6 +56,9 @@ public class ThingsboardInstallService {
@Autowired
private SystemDataLoaderService systemDataLoaderService;
@Autowired
private DataUpdateService dataUpdateService;
public void performInstall() {
try {
if (isUpgrade) {
@ -87,6 +85,8 @@ public class ThingsboardInstallService {
databaseUpgradeService.upgradeDatabase("1.4.0");
dataUpdateService.updateData("1.4.0");
log.info("Updating system data...");
systemDataLoaderService.deleteSystemWidgetBundle("charts");
@ -113,13 +113,6 @@ public class ThingsboardInstallService {
log.info("Starting ThingsBoard Installation...");
if (this.dataDir == null) {
throw new RuntimeException("'install.data_dir' property should specified!");
}
if (!Paths.get(this.dataDir).toFile().isDirectory()) {
throw new RuntimeException("'install.data_dir' property value is not a valid directory!");
}
log.info("Installing DataBase schema...");
databaseSchemaService.createDatabaseSchema();

View File

@ -37,17 +37,16 @@ public class CassandraDatabaseSchemaService implements DatabaseSchemaService {
private static final String CASSANDRA_DIR = "cassandra";
private static final String SCHEMA_CQL = "schema.cql";
@Value("${install.data_dir}")
private String dataDir;
@Autowired
private CassandraInstallCluster cluster;
@Autowired
private InstallScripts installScripts;
@Override
public void createDatabaseSchema() throws Exception {
log.info("Installing Cassandra DataBase schema...");
Path schemaFile = Paths.get(this.dataDir, CASSANDRA_DIR, SCHEMA_CQL);
Path schemaFile = Paths.get(installScripts.getDataDir(), CASSANDRA_DIR, SCHEMA_CQL);
loadCql(schemaFile);
}

View File

@ -43,9 +43,6 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
private static final String SCHEMA_UPDATE_CQL = "schema_update.cql";
@Value("${install.data_dir}")
private String dataDir;
@Autowired
private CassandraCluster cluster;
@ -55,6 +52,9 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
@Autowired
private DashboardService dashboardService;
@Autowired
private InstallScripts installScripts;
@Override
public void upgradeDatabase(String fromVersion) throws Exception {
@ -91,7 +91,7 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
log.info("Relations dumped.");
log.info("Updating schema ...");
Path schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.3.0", SCHEMA_UPDATE_CQL);
Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.3.0", SCHEMA_UPDATE_CQL);
loadCql(schemaUpdateFile);
log.info("Schema updated.");
@ -173,7 +173,7 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
log.info("Updating schema ...");
schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.4.0", SCHEMA_UPDATE_CQL);
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.4.0", SCHEMA_UPDATE_CQL);
loadCql(schemaUpdateFile);
log.info("Schema updated.");
@ -189,7 +189,7 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
case "1.4.0":
log.info("Updating schema ...");
schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.5.0", SCHEMA_UPDATE_CQL);
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.5.0", SCHEMA_UPDATE_CQL);
loadCql(schemaUpdateFile);
log.info("Schema updated.");

View File

@ -0,0 +1,22 @@
/**
* 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.server.service.install;
public interface DataUpdateService {
void updateData(String fromVersion) throws Exception;
}

View File

@ -0,0 +1,106 @@
/**
* 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.server.service.install;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.IdBased;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.tenant.TenantService;
import java.util.List;
import java.util.UUID;
@Service
@Profile("install")
@Slf4j
public class DefaultDataUpdateService implements DataUpdateService {
@Autowired
private TenantService tenantService;
@Autowired
private RuleChainService ruleChainService;
@Autowired
private InstallScripts installScripts;
@Override
public void updateData(String fromVersion) throws Exception {
switch (fromVersion) {
case "1.4.0":
log.info("Updating data from version 1.4.0 to 1.5.0 ...");
tenantsDefaultRuleChainUpdater.updateEntities(null);
break;
default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
}
}
private PaginatedUpdater<String, Tenant> tenantsDefaultRuleChainUpdater =
new PaginatedUpdater<String, Tenant>() {
@Override
protected List<Tenant> findEntities(String region, TextPageLink pageLink) {
return tenantService.findTenants(pageLink).getData();
}
@Override
protected void updateEntity(Tenant tenant) {
try {
RuleChain ruleChain = ruleChainService.getRootTenantRuleChain(tenant.getId());
if (ruleChain == null) {
installScripts.createDefaultRuleChains(tenant.getId());
}
} catch (Exception e) {
log.error("Unable to update Tenant", e);
}
}
};
public abstract class PaginatedUpdater<I, D extends IdBased<?>> {
private static final int DEFAULT_LIMIT = 100;
public void updateEntities(I id) {
TextPageLink pageLink = new TextPageLink(DEFAULT_LIMIT);
boolean hasNext = true;
while (hasNext) {
List<D> entities = findEntities(id, pageLink);
for (D entity : entities) {
updateEntity(entity);
}
hasNext = entities.size() == pageLink.getLimit();
if (hasNext) {
int index = entities.size() - 1;
UUID idOffset = entities.get(index).getUuidId();
pageLink.setIdOffset(idOffset);
}
}
}
protected abstract List<D> findEntities(I id, TextPageLink pageLink);
protected abstract void updateEntity(D entity);
}
}

View File

@ -84,6 +84,9 @@ public class InstallScripts {
public String getDataDir() {
if (!StringUtils.isEmpty(dataDir)) {
if (!Paths.get(this.dataDir).toFile().isDirectory()) {
throw new RuntimeException("'install.data_dir' property value is not a valid directory!");
}
return dataDir;
} else {
String workDir = System.getProperty("user.dir");

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.service.install;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
@ -38,9 +39,6 @@ public class SqlDatabaseSchemaService implements DatabaseSchemaService {
private static final String SQL_DIR = "sql";
private static final String SCHEMA_SQL = "schema.sql";
@Value("${install.data_dir}")
private String dataDir;
@Value("${spring.datasource.url}")
private String dbUrl;
@ -50,12 +48,15 @@ public class SqlDatabaseSchemaService implements DatabaseSchemaService {
@Value("${spring.datasource.password}")
private String dbPassword;
@Autowired
private InstallScripts installScripts;
@Override
public void createDatabaseSchema() throws Exception {
log.info("Installing SQL DataBase schema...");
Path schemaFile = Paths.get(this.dataDir, SQL_DIR, SCHEMA_SQL);
Path schemaFile = Paths.get(installScripts.getDataDir(), SQL_DIR, SCHEMA_SQL);
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8"));
conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to load initial thingsboard database schema

View File

@ -44,9 +44,6 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
private static final String SCHEMA_UPDATE_SQL = "schema_update.sql";
@Value("${install.data_dir}")
private String dataDir;
@Value("${spring.datasource.url}")
private String dbUrl;
@ -59,12 +56,15 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
@Autowired
private DashboardService dashboardService;
@Autowired
private InstallScripts installScripts;
@Override
public void upgradeDatabase(String fromVersion) throws Exception {
switch (fromVersion) {
case "1.3.0":
log.info("Updating schema ...");
Path schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.3.1", SCHEMA_UPDATE_SQL);
Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.3.1", SCHEMA_UPDATE_SQL);
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8"));
conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
@ -82,7 +82,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
log.info("Dashboards dumped.");
log.info("Updating schema ...");
schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.4.0", SCHEMA_UPDATE_SQL);
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.4.0", SCHEMA_UPDATE_SQL);
String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8"));
conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
log.info("Schema updated.");
@ -100,7 +100,7 @@ public class SqlDatabaseUpgradeService implements DatabaseUpgradeService {
case "1.4.0":
try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
log.info("Updating schema ...");
schemaUpdateFile = Paths.get(this.dataDir, "upgrade", "1.5.0", SCHEMA_UPDATE_SQL);
schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "1.5.0", SCHEMA_UPDATE_SQL);
String sql = new String(Files.readAllBytes(schemaUpdateFile), Charset.forName("UTF-8"));
conn.createStatement().execute(sql); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
log.info("Schema updated.");

View File

@ -0,0 +1,35 @@
/**
* 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.api;
import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Data
public class EmptyNodeConfiguration implements NodeConfiguration<EmptyNodeConfiguration> {
private int version;
@Override
public EmptyNodeConfiguration defaultConfiguration() {
EmptyNodeConfiguration configuration = new EmptyNodeConfiguration();
return configuration;
}
}

View File

@ -26,7 +26,7 @@ public class TbLogNodeConfiguration implements NodeConfiguration {
@Override
public TbLogNodeConfiguration defaultConfiguration() {
TbLogNodeConfiguration configuration = new TbLogNodeConfiguration();
configuration.setJsScript("return 'incoming message = ' + msg + meta;");
configuration.setJsScript("return 'Incoming message:\\n' + JSON.stringify(msg) + '\\nIncoming metadata:\\n' + JSON.stringify(metadata);");
return configuration;
}
}

View File

@ -31,8 +31,7 @@ import org.thingsboard.server.common.msg.TbMsg;
configClazz = TbMsgTypeFilterNodeConfiguration.class,
relationTypes = {"True", "False"},
nodeDescription = "Filter incoming messages by Message Type",
nodeDetails = "Evaluate incoming Message with configured JS condition. " +
"If incoming MessageType is expected - send Message via <b>Success</b> chain, otherwise <b>Failure</b> chain is used.",
nodeDetails = "If incoming MessageType is expected - send Message via <b>Success</b> chain, otherwise <b>Failure</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbFilterNodeMessageTypeConfig")
public class TbMsgTypeFilterNode implements TbNode {

View File

@ -0,0 +1,63 @@
/**
* 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.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.session.SessionMsgType;
@Slf4j
@RuleNode(
type = ComponentType.FILTER,
name = "message type switch",
configClazz = EmptyNodeConfiguration.class,
relationTypes = {"Post attributes", "Post telemetry", "RPC Request", "Other"},
nodeDescription = "Route incoming messages by Message Type",
nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> via corresponding chain, otherwise <b>Other</b> chain is used.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "tbNodeEmptyConfig")
public class TbMsgTypeSwitchNode 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;
if (msg.getType().equals(SessionMsgType.POST_ATTRIBUTES_REQUEST.name())) {
relationType = "Post attributes";
} else if (msg.getType().equals(SessionMsgType.POST_TELEMETRY_REQUEST.name())) {
relationType = "Post telemetry";
} else if (msg.getType().equals(SessionMsgType.TO_SERVER_RPC_REQUEST.name())) {
relationType = "RPC Request";
} else {
relationType = "Other";
}
ctx.tellNext(msg, relationType);
}
@Override
public void destroy() {
}
}

View File

@ -46,7 +46,9 @@ import java.util.Set;
name = "save attributes",
configClazz = TbMsgAttributesNodeConfiguration.class,
nodeDescription = "Saves attributes data",
nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type"
nodeDetails = "Saves entity attributes based on configurable scope parameter. Expects messages with 'POST_ATTRIBUTES_REQUEST' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeAttributesConfig"
)
public class TbMsgAttributesNode implements TbNode {

View File

@ -45,7 +45,7 @@ import java.util.Map;
nodeDescription = "Saves timeseries data",
nodeDetails = "Saves timeseries telemetry data based on configurable TTL parameter. Expects messages with 'POST_TELEMETRY_REQUEST' message type",
uiResources = {"static/rulenode/rulenode-core-config.js", "static/rulenode/rulenode-core-config.css"},
configDirective = "tbActionNodeTelemetryConfig"
configDirective = "tbActionNodeTimeseriesConfig"
)
public class TbMsgTimeseriesNode implements TbNode {

View File

@ -316,6 +316,7 @@ export default function ImportExport($log, $translate, $q, $mdDialog, $document,
delete ruleChainMetaData.ruleChainId;
for (var i=0;i<ruleChainMetaData.nodes.length;i++) {
var node = ruleChainMetaData.nodes[i];
delete node.ruleChainId;
ruleChainMetaData.nodes[i] = prepareExport(node);
}
return ruleChainMetaData;