Merge remote-tracking branch 'origin/develop/1.5' into feature/rpc-refactoring
This commit is contained in:
commit
eb6f0f394e
@ -59,6 +59,7 @@ import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
|
|||||||
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
|
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
|
||||||
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
|
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
|
||||||
import org.thingsboard.server.service.component.ComponentDiscoveryService;
|
import org.thingsboard.server.service.component.ComponentDiscoveryService;
|
||||||
|
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
|
||||||
import org.thingsboard.server.service.mail.MailExecutorService;
|
import org.thingsboard.server.service.mail.MailExecutorService;
|
||||||
import org.thingsboard.server.service.script.JsExecutorService;
|
import org.thingsboard.server.service.script.JsExecutorService;
|
||||||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
|
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
|
||||||
@ -173,6 +174,10 @@ public class ActorSystemContext {
|
|||||||
@Getter
|
@Getter
|
||||||
private MailExecutorService mailExecutor;
|
private MailExecutorService mailExecutor;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Getter
|
||||||
|
private DbCallbackExecutorService dbCallbackExecutor;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Getter
|
@Getter
|
||||||
private MailService mailService;
|
private MailService mailService;
|
||||||
|
|||||||
@ -137,6 +137,11 @@ class DefaultTbContext implements TbContext {
|
|||||||
return mainCtx.getMailExecutor();
|
return mainCtx.getMailExecutor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListeningExecutor getDbCallbackExecutor() {
|
||||||
|
return mainCtx.getDbCallbackExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) {
|
public ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames) {
|
||||||
return new NashornJsEngine(script, functionName, argNames);
|
return new NashornJsEngine(script, functionName, argNames);
|
||||||
|
|||||||
@ -253,6 +253,13 @@ public class RuleChainController extends BaseController {
|
|||||||
Set<String> states = engine.executeSwitch(inMsg);
|
Set<String> states = engine.executeSwitch(inMsg);
|
||||||
output = objectMapper.writeValueAsString(states);
|
output = objectMapper.writeValueAsString(states);
|
||||||
break;
|
break;
|
||||||
|
case "json":
|
||||||
|
JsonNode json = engine.executeJson(inMsg);
|
||||||
|
output = objectMapper.writeValueAsString(json);
|
||||||
|
break;
|
||||||
|
case "string":
|
||||||
|
output = engine.executeToString(inMsg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unsupported script type: " + scriptType);
|
throw new IllegalArgumentException("Unsupported script type: " + scriptType);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* 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.executors;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import org.thingsboard.rule.engine.api.ListeningExecutor;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by igor on 4/13/18.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractListeningExecutor implements ListeningExecutor {
|
||||||
|
|
||||||
|
private ListeningExecutorService service;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
this.service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(getThreadPollSize()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
if (this.service != null) {
|
||||||
|
this.service.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> ListenableFuture<T> executeAsync(Callable<T> task) {
|
||||||
|
return service.submit(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable command) {
|
||||||
|
service.execute(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int getThreadPollSize();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 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.executors;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DbCallbackExecutorService extends AbstractListeningExecutor {
|
||||||
|
|
||||||
|
@Value("${actors.rule.db_callback_thread_pool_size}")
|
||||||
|
private int dbCallbackExecutorThreadPoolSize;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getThreadPollSize() {
|
||||||
|
return dbCallbackExecutorThreadPoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -15,40 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.service.mail;
|
package org.thingsboard.server.service.mail;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
|
||||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.thingsboard.rule.engine.api.ListeningExecutor;
|
import org.thingsboard.server.service.executors.AbstractListeningExecutor;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class MailExecutorService implements ListeningExecutor {
|
public class MailExecutorService extends AbstractListeningExecutor {
|
||||||
|
|
||||||
@Value("${actors.rule.mail_thread_pool_size}")
|
@Value("${actors.rule.mail_thread_pool_size}")
|
||||||
private int mailExecutorThreadPoolSize;
|
private int mailExecutorThreadPoolSize;
|
||||||
|
|
||||||
private ListeningExecutorService service;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
this.service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(mailExecutorThreadPoolSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
public void destroy() {
|
|
||||||
if (this.service != null) {
|
|
||||||
this.service.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ListenableFuture<T> executeAsync(Callable<T> task) {
|
protected int getThreadPollSize() {
|
||||||
return service.submit(task);
|
return mailExecutorThreadPoolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,41 +15,19 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.service.script;
|
package org.thingsboard.server.service.script;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
|
||||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.thingsboard.rule.engine.api.ListeningExecutor;
|
import org.thingsboard.server.service.executors.AbstractListeningExecutor;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class JsExecutorService implements ListeningExecutor{
|
public class JsExecutorService extends AbstractListeningExecutor {
|
||||||
|
|
||||||
@Value("${actors.rule.js_thread_pool_size}")
|
@Value("${actors.rule.js_thread_pool_size}")
|
||||||
private int jsExecutorThreadPoolSize;
|
private int jsExecutorThreadPoolSize;
|
||||||
|
|
||||||
private ListeningExecutorService service;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
this.service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(jsExecutorThreadPoolSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
public void destroy() {
|
|
||||||
if (this.service != null) {
|
|
||||||
this.service.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ListenableFuture<T> executeAsync(Callable<T> task) {
|
protected int getThreadPollSize() {
|
||||||
return service.submit(task);
|
return jsExecutorThreadPoolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,6 +153,10 @@ public class NashornJsEngine implements org.thingsboard.rule.engine.api.ScriptEn
|
|||||||
@Override
|
@Override
|
||||||
public String executeToString(TbMsg msg) throws ScriptException {
|
public String executeToString(TbMsg msg) throws ScriptException {
|
||||||
JsonNode result = executeScript(msg);
|
JsonNode result = executeScript(msg);
|
||||||
|
if (!result.isTextual()) {
|
||||||
|
log.warn("Wrong result type: {}", result.getNodeType());
|
||||||
|
throw new ScriptException("Wrong result type: " + result.getNodeType());
|
||||||
|
}
|
||||||
return result.asText();
|
return result.asText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -219,8 +219,11 @@ actors:
|
|||||||
termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}"
|
termination.delay: "${ACTORS_RULE_TERMINATION_DELAY:30000}"
|
||||||
# Errors for particular actor are persisted once per specified amount of milliseconds
|
# Errors for particular actor are persisted once per specified amount of milliseconds
|
||||||
error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}"
|
error_persist_frequency: "${ACTORS_RULE_ERROR_FREQUENCY:3000}"
|
||||||
|
# Specify thread pool size for database request callbacks executor service
|
||||||
|
db_callback_thread_pool_size: "${ACTORS_RULE_DB_CALLBACK_THREAD_POOL_SIZE:1}"
|
||||||
# Specify thread pool size for javascript executor service
|
# Specify thread pool size for javascript executor service
|
||||||
js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:10}"
|
js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:10}"
|
||||||
|
# Specify thread pool size for mail sender executor service
|
||||||
mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:10}"
|
mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:10}"
|
||||||
chain:
|
chain:
|
||||||
# Errors for particular actor are persisted once per specified amount of milliseconds
|
# Errors for particular actor are persisted once per specified amount of milliseconds
|
||||||
|
|||||||
@ -18,8 +18,9 @@ package org.thingsboard.rule.engine.api;
|
|||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public interface ListeningExecutor {
|
public interface ListeningExecutor extends Executor {
|
||||||
|
|
||||||
<T> ListenableFuture<T> executeAsync(Callable<T> task);
|
<T> ListenableFuture<T> executeAsync(Callable<T> task);
|
||||||
|
|
||||||
|
|||||||
@ -88,6 +88,8 @@ public interface TbContext {
|
|||||||
|
|
||||||
ListeningExecutor getMailExecutor();
|
ListeningExecutor getMailExecutor();
|
||||||
|
|
||||||
|
ListeningExecutor getDbCallbackExecutor();
|
||||||
|
|
||||||
MailService getMailService();
|
MailService getMailService();
|
||||||
|
|
||||||
ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames);
|
ScriptEngine createJsScriptEngine(String script, String functionName, String... argNames);
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright © 2016-2018 The Thingsboard Authors
|
* Copyright © 2016-2018 The Thingsboard Authors
|
||||||
*
|
* <p>
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
* <p>
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
* <p>
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -32,6 +32,8 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
|
|||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
import org.thingsboard.server.common.msg.TbMsgMetaData;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -47,7 +49,8 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
|||||||
"If alarm was not created, original message is returned. Otherwise new Message returned with type 'ALARM', Alarm object in 'msg' property and 'matadata' will contains one of those properties 'isNewAlarm/isExistingAlarm/isClearedAlarm' " +
|
"If alarm was not created, original message is returned. Otherwise new Message returned with type 'ALARM', Alarm object in 'msg' property and 'matadata' will contains one of those properties 'isNewAlarm/isExistingAlarm/isClearedAlarm' " +
|
||||||
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
||||||
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>",
|
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>",
|
||||||
uiResources = {"static/rulenode/rulenode-core-config.js"})
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
|
configDirective = "tbActionNodeAlarmConfig")
|
||||||
|
|
||||||
public class TbAlarmNode implements TbNode {
|
public class TbAlarmNode implements TbNode {
|
||||||
|
|
||||||
@ -81,7 +84,7 @@ public class TbAlarmNode implements TbNode {
|
|||||||
} else {
|
} else {
|
||||||
return checkForClearIfExist(ctx, msg);
|
return checkForClearIfExist(ctx, msg);
|
||||||
}
|
}
|
||||||
});
|
}, ctx.getDbCallbackExecutor());
|
||||||
|
|
||||||
withCallback(transform,
|
withCallback(transform,
|
||||||
alarmResult -> {
|
alarmResult -> {
|
||||||
@ -107,7 +110,7 @@ public class TbAlarmNode implements TbNode {
|
|||||||
} else {
|
} else {
|
||||||
return updateAlarm(ctx, msg, a);
|
return updateAlarm(ctx, msg, a);
|
||||||
}
|
}
|
||||||
});
|
}, ctx.getDbCallbackExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFuture<AlarmResult> checkForClearIfExist(TbContext ctx, TbMsg msg) {
|
private ListenableFuture<AlarmResult> checkForClearIfExist(TbContext ctx, TbMsg msg) {
|
||||||
@ -117,12 +120,14 @@ public class TbAlarmNode implements TbNode {
|
|||||||
return clearAlarm(ctx, msg, a);
|
return clearAlarm(ctx, msg, a);
|
||||||
}
|
}
|
||||||
return Futures.immediateFuture(new AlarmResult(false, false, false, null));
|
return Futures.immediateFuture(new AlarmResult(false, false, false, null));
|
||||||
});
|
}, ctx.getDbCallbackExecutor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFuture<AlarmResult> createNewAlarm(TbContext ctx, TbMsg msg) {
|
private ListenableFuture<AlarmResult> createNewAlarm(TbContext ctx, TbMsg msg) {
|
||||||
ListenableFuture<Alarm> asyncAlarm = Futures.transform(buildAlarmDetails(ctx, msg), (Function<JsonNode, Alarm>) details -> buildAlarm(msg, details, ctx.getTenantId()));
|
ListenableFuture<Alarm> asyncAlarm = Futures.transform(buildAlarmDetails(ctx, msg),
|
||||||
ListenableFuture<Alarm> asyncCreated = Futures.transform(asyncAlarm, (Function<Alarm, Alarm>) alarm -> ctx.getAlarmService().createOrUpdateAlarm(alarm));
|
(Function<JsonNode, Alarm>) details -> buildAlarm(msg, details, ctx.getTenantId()));
|
||||||
|
ListenableFuture<Alarm> asyncCreated = Futures.transform(asyncAlarm,
|
||||||
|
(Function<Alarm, Alarm>) alarm -> ctx.getAlarmService().createOrUpdateAlarm(alarm), ctx.getDbCallbackExecutor());
|
||||||
return Futures.transform(asyncCreated, (Function<Alarm, AlarmResult>) alarm -> new AlarmResult(true, false, false, alarm));
|
return Futures.transform(asyncCreated, (Function<Alarm, AlarmResult>) alarm -> new AlarmResult(true, false, false, alarm));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +138,7 @@ public class TbAlarmNode implements TbNode {
|
|||||||
alarm.setDetails(details);
|
alarm.setDetails(details);
|
||||||
alarm.setEndTs(System.currentTimeMillis());
|
alarm.setEndTs(System.currentTimeMillis());
|
||||||
return ctx.getAlarmService().createOrUpdateAlarm(alarm);
|
return ctx.getAlarmService().createOrUpdateAlarm(alarm);
|
||||||
});
|
}, ctx.getDbCallbackExecutor());
|
||||||
|
|
||||||
return Futures.transform(asyncUpdated, (Function<Alarm, AlarmResult>) a -> new AlarmResult(false, true, false, a));
|
return Futures.transform(asyncUpdated, (Function<Alarm, AlarmResult>) a -> new AlarmResult(false, true, false, a));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,9 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
|
|||||||
nodeDescription = "Log incoming messages using JS script for transformation Message into String",
|
nodeDescription = "Log incoming messages using JS script for transformation Message into String",
|
||||||
nodeDetails = "Transform incoming Message with configured JS condition to String and log final value. " +
|
nodeDetails = "Transform incoming Message with configured JS condition to String and log final value. " +
|
||||||
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
"Message payload can be accessed via <code>msg</code> property. For example <code>'temperature = ' + msg.temperature ;</code>" +
|
||||||
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>")
|
"Message metadata can be accessed via <code>metadata</code> property. For example <code>'name = ' + metadata.customerName;</code>",
|
||||||
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
|
configDirective = "tbActionNodeLogConfig")
|
||||||
|
|
||||||
public class TbLogNode implements TbNode {
|
public class TbLogNode implements TbNode {
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,9 @@ import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
|
|||||||
configClazz = TbMsgToEmailNodeConfiguration.class,
|
configClazz = TbMsgToEmailNodeConfiguration.class,
|
||||||
nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity",
|
nodeDescription = "Change Message Originator To Tenant/Customer/Related Entity",
|
||||||
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
nodeDetails = "Related Entity found using configured relation direction and Relation Type. " +
|
||||||
"If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ")
|
"If multiple Related Entities are found, only first Entity is used as new Originator, other entities are discarded. ",
|
||||||
|
uiResources = {"static/rulenode/rulenode-core-config.js"},
|
||||||
|
configDirective = "tbTransformationNodeToEmailConfig")
|
||||||
public class TbMsgToEmailNode implements TbNode {
|
public class TbMsgToEmailNode implements TbNode {
|
||||||
|
|
||||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -62,6 +62,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
|||||||
vm.isEditingRuleNodeLink = false;
|
vm.isEditingRuleNodeLink = false;
|
||||||
|
|
||||||
vm.isLibraryOpen = true;
|
vm.isLibraryOpen = true;
|
||||||
|
vm.enableHotKeys = true;
|
||||||
|
|
||||||
Object.defineProperty(vm, 'isLibraryOpenReadonly', {
|
Object.defineProperty(vm, 'isLibraryOpenReadonly', {
|
||||||
get: function() { return vm.isLibraryOpen },
|
get: function() { return vm.isLibraryOpen },
|
||||||
@ -327,66 +328,80 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
|||||||
description: $translate.instant('rulenode.select-all-objects'),
|
description: $translate.instant('rulenode.select-all-objects'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
vm.modelservice.selectAll();
|
vm.modelservice.selectAll();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.add({
|
.add({
|
||||||
combo: 'ctrl+c',
|
combo: 'ctrl+c',
|
||||||
description: $translate.instant('rulenode.copy-selected'),
|
description: $translate.instant('rulenode.copy-selected'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
copyRuleNodes();
|
copyRuleNodes();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.add({
|
.add({
|
||||||
combo: 'ctrl+v',
|
combo: 'ctrl+v',
|
||||||
description: $translate.instant('action.paste'),
|
description: $translate.instant('action.paste'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (itembuffer.hasRuleNodes()) {
|
if (itembuffer.hasRuleNodes()) {
|
||||||
pasteRuleNodes();
|
pasteRuleNodes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.add({
|
.add({
|
||||||
combo: 'esc',
|
combo: 'esc',
|
||||||
description: $translate.instant('rulenode.deselect-all-objects'),
|
description: $translate.instant('rulenode.deselect-all-objects'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
vm.modelservice.deselectAll();
|
vm.modelservice.deselectAll();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.add({
|
.add({
|
||||||
combo: 'ctrl+s',
|
combo: 'ctrl+s',
|
||||||
description: $translate.instant('action.apply'),
|
description: $translate.instant('action.apply'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
vm.saveRuleChain();
|
vm.saveRuleChain();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.add({
|
.add({
|
||||||
combo: 'ctrl+z',
|
combo: 'ctrl+z',
|
||||||
description: $translate.instant('action.decline-changes'),
|
description: $translate.instant('action.decline-changes'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
vm.revertRuleChain();
|
vm.revertRuleChain();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.add({
|
.add({
|
||||||
combo: 'del',
|
combo: 'del',
|
||||||
description: $translate.instant('rulenode.delete-selected-objects'),
|
description: $translate.instant('rulenode.delete-selected-objects'),
|
||||||
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
allowIn: ['INPUT', 'SELECT', 'TEXTAREA'],
|
||||||
callback: function (event) {
|
callback: function (event) {
|
||||||
|
if (vm.enableHotKeys) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
vm.modelservice.deleteSelected();
|
vm.modelservice.deleteSelected();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,6 +589,7 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
|||||||
$scope.$watch(function() {
|
$scope.$watch(function() {
|
||||||
return vm.isEditingRuleNode || vm.isEditingRuleNodeLink;
|
return vm.isEditingRuleNode || vm.isEditingRuleNodeLink;
|
||||||
}, (val) => {
|
}, (val) => {
|
||||||
|
vm.enableHotKeys = !val;
|
||||||
updateErrorTooltips(val);
|
updateErrorTooltips(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -605,12 +621,15 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var labels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component);
|
var labels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component);
|
||||||
|
vm.enableHotKeys = false;
|
||||||
addRuleNodeLink(event, edge, labels).then(
|
addRuleNodeLink(event, edge, labels).then(
|
||||||
(link) => {
|
(link) => {
|
||||||
deferred.resolve(link);
|
deferred.resolve(link);
|
||||||
|
vm.enableHotKeys = true;
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
deferred.reject();
|
deferred.reject();
|
||||||
|
vm.enableHotKeys = true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1159,6 +1178,8 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
|||||||
|
|
||||||
var ruleChainId = vm.ruleChain.id ? vm.ruleChain.id.id : null;
|
var ruleChainId = vm.ruleChain.id ? vm.ruleChain.id.id : null;
|
||||||
|
|
||||||
|
vm.enableHotKeys = false;
|
||||||
|
|
||||||
$mdDialog.show({
|
$mdDialog.show({
|
||||||
controller: 'AddRuleNodeController',
|
controller: 'AddRuleNodeController',
|
||||||
controllerAs: 'vm',
|
controllerAs: 'vm',
|
||||||
@ -1188,7 +1209,9 @@ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $time
|
|||||||
}
|
}
|
||||||
vm.ruleChainModel.nodes.push(ruleNode);
|
vm.ruleChainModel.nodes.push(ruleNode);
|
||||||
updateRuleNodesHighlight();
|
updateRuleNodesHighlight();
|
||||||
|
vm.enableHotKeys = true;
|
||||||
}, function () {
|
}, function () {
|
||||||
|
vm.enableHotKeys = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user