Browse Source

Improve email Rule Nodes configuration.

pull/804/head
Igor Kulikov 8 years ago
parent
commit
8c481f20e0
  1. 10
      rule-engine/rule-engine-components/pom.xml
  2. 68
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/RuleVelocityUtils.java
  3. 44
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java
  4. 7
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeConfiguration.java
  5. 68
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java
  6. 16
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNodeConfiguration.java
  7. 6
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

10
rule-engine/rule-engine-components/pom.xml

@ -72,16 +72,6 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>

68
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/RuleVelocityUtils.java

@ -1,68 +0,0 @@
/**
* 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.mail;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.RuntimeSingleton;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.thingsboard.server.common.msg.TbMsg;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Map;
import static org.thingsboard.server.common.msg.TbMsgDataType.JSON;
public class RuleVelocityUtils {
public static VelocityContext createContext(TbMsg msg) throws IOException {
VelocityContext context = new VelocityContext();
context.put("originator", msg.getOriginator());
context.put("type", msg.getType());
context.put("metadata", msg.getMetaData().values());
if (msg.getDataType() == JSON) {
Map map = new ObjectMapper().readValue(msg.getData(), Map.class);
context.put("msg", map);
} else {
context.put("msg", msg.getData());
}
return context;
}
public static String merge(Template template, VelocityContext context) {
StringWriter writer = new StringWriter();
template.merge(context, writer);
return writer.toString();
}
public static Template create(String source, String templateName) throws ParseException {
RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(source);
SimpleNode node = runtimeServices.parse(reader, templateName);
Template template = new Template();
template.setRuntimeServices(runtimeServices);
template.setData(node);
template.initDocument();
return template;
}
}

44
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNode.java

@ -18,17 +18,14 @@ package org.thingsboard.rule.engine.mail;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.runtime.parser.ParseException;
import org.springframework.util.StringUtils;
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.TbMsgMetaData;
import java.io.IOException;
import java.util.Optional;
import static org.thingsboard.rule.engine.mail.TbSendEmailNode.SEND_EMAIL_TYPE;
@ -48,27 +45,9 @@ public class TbMsgToEmailNode implements TbNode {
private TbMsgToEmailNodeConfiguration config;
private Optional<Template> fromTemplate;
private Optional<Template> toTemplate;
private Optional<Template> ccTemplate;
private Optional<Template> bccTemplate;
private Optional<Template> subjectTemplate;
private Optional<Template> bodyTemplate;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbMsgToEmailNodeConfiguration.class);
try {
fromTemplate = toTemplate(config.getFromTemplate(), "From Template");
toTemplate = toTemplate(config.getToTemplate(), "To Template");
ccTemplate = toTemplate(config.getCcTemplate(), "Cc Template");
bccTemplate = toTemplate(config.getBccTemplate(), "Bcc Template");
subjectTemplate = toTemplate(config.getSubjectTemplate(), "Subject Template");
bodyTemplate = toTemplate(config.getBodyTemplate(), "Body Template");
} catch (ParseException e) {
log.error("Failed to create templates based on provided configuration!", e);
throw new TbNodeException(e);
}
}
@Override
@ -90,21 +69,20 @@ public class TbMsgToEmailNode implements TbNode {
private EmailPojo convert(TbMsg msg) throws IOException {
EmailPojo.EmailPojoBuilder builder = EmailPojo.builder();
VelocityContext context = RuleVelocityUtils.createContext(msg);
fromTemplate.ifPresent(t -> builder.from(RuleVelocityUtils.merge(t, context)));
toTemplate.ifPresent(t -> builder.to(RuleVelocityUtils.merge(t, context)));
ccTemplate.ifPresent(t -> builder.cc(RuleVelocityUtils.merge(t, context)));
bccTemplate.ifPresent(t -> builder.bcc(RuleVelocityUtils.merge(t, context)));
subjectTemplate.ifPresent(t -> builder.subject(RuleVelocityUtils.merge(t, context)));
bodyTemplate.ifPresent(t -> builder.body(RuleVelocityUtils.merge(t, context)));
builder.from(fromTemplate(this.config.getFromTemplate(), msg.getMetaData()));
builder.to(fromTemplate(this.config.getToTemplate(), msg.getMetaData()));
builder.cc(fromTemplate(this.config.getCcTemplate(), msg.getMetaData()));
builder.bcc(fromTemplate(this.config.getBccTemplate(), msg.getMetaData()));
builder.subject(fromTemplate(this.config.getSubjectTemplate(), msg.getMetaData()));
builder.body(fromTemplate(this.config.getBodyTemplate(), msg.getMetaData()));
return builder.build();
}
private Optional<Template> toTemplate(String source, String name) throws ParseException {
if (!StringUtils.isEmpty(source)) {
return Optional.of(RuleVelocityUtils.create(source, name));
private String fromTemplate(String template, TbMsgMetaData metaData) {
if (!StringUtils.isEmpty(template)) {
return TbNodeUtils.processPattern(template, metaData);
} else {
return Optional.empty();
return null;
}
}

7
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbMsgToEmailNodeConfiguration.java

@ -32,10 +32,9 @@ public class TbMsgToEmailNodeConfiguration implements NodeConfiguration {
public TbMsgToEmailNodeConfiguration defaultConfiguration() {
TbMsgToEmailNodeConfiguration configuration = new TbMsgToEmailNodeConfiguration();
configuration.fromTemplate = "info@testmail.org";
configuration.toTemplate = "$metadata.userEmail";
configuration.subjectTemplate = "Device $deviceType temperature high";
configuration.bodyTemplate = "Device $metadata.deviceName has high temperature $msg.temp";
configuration.toTemplate = "${userEmail}";
configuration.subjectTemplate = "Device ${deviceType} temperature high";
configuration.bodyTemplate = "Device ${deviceName} has high temperature ${temp}";
return configuration;
}
}

68
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java

@ -15,15 +15,21 @@
*/
package org.thingsboard.rule.engine.mail;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
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 javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.util.Properties;
import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
@ -35,17 +41,29 @@ import static org.thingsboard.rule.engine.DonAsynchron.withCallback;
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. " +
"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 = "tbActionNodeSendEmailConfig"
)
public class TbSendEmailNode implements TbNode {
private static final String MAIL_PROP = "mail.";
static final String SEND_EMAIL_TYPE = "SEND_EMAIL";
private static final ObjectMapper MAPPER = new ObjectMapper();
private TbSendEmailNodeConfiguration config;
private JavaMailSenderImpl mailSender;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbSendEmailNodeConfiguration.class);
try {
this.config = TbNodeUtils.convert(configuration, TbSendEmailNodeConfiguration.class);
if (!this.config.isUseSystemSmtpSettings()) {
mailSender = createMailSender();
}
} catch (Exception e) {
throw new TbNodeException(e);
}
}
@Override
@ -54,8 +72,7 @@ public class TbSendEmailNode implements TbNode {
validateType(msg.getType());
EmailPojo email = getEmail(msg);
withCallback(ctx.getMailExecutor().executeAsync(() -> {
ctx.getMailService().send(email.getFrom(), email.getTo(), email.getCc(),
email.getBcc(), email.getSubject(), email.getBody());
sendEmail(ctx, email);
return null;
}),
ok -> ctx.tellNext(msg),
@ -65,6 +82,27 @@ public class TbSendEmailNode implements TbNode {
}
}
private void sendEmail(TbContext ctx, EmailPojo email) throws Exception {
if (this.config.isUseSystemSmtpSettings()) {
ctx.getMailService().send(email.getFrom(), email.getTo(), email.getCc(),
email.getBcc(), email.getSubject(), email.getBody());
} else {
MimeMessage mailMsg = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mailMsg, "UTF-8");
helper.setFrom(email.getFrom());
helper.setTo(email.getTo().split("\\s*,\\s*"));
if (!StringUtils.isBlank(email.getCc())) {
helper.setCc(email.getCc().split("\\s*,\\s*"));
}
if (!StringUtils.isBlank(email.getBcc())) {
helper.setBcc(email.getBcc().split("\\s*,\\s*"));
}
helper.setSubject(email.getSubject());
helper.setText(email.getBody());
mailSender.send(helper.getMimeMessage());
}
}
private EmailPojo getEmail(TbMsg msg) throws IOException {
EmailPojo email = MAPPER.readValue(msg.getData(), EmailPojo.class);
if (StringUtils.isBlank(email.getTo())) {
@ -83,4 +121,26 @@ public class TbSendEmailNode implements TbNode {
@Override
public void destroy() {
}
private JavaMailSenderImpl createMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(this.config.getSmtpHost());
mailSender.setPort(this.config.getSmtpPort());
mailSender.setUsername(this.config.getUsername());
mailSender.setPassword(this.config.getPassword());
mailSender.setJavaMailProperties(createJavaMailProperties());
return mailSender;
}
private Properties createJavaMailProperties() {
Properties javaMailProperties = new Properties();
String protocol = this.config.getSmtpProtocol();
javaMailProperties.put("mail.transport.protocol", protocol);
javaMailProperties.put(MAIL_PROP + protocol + ".host", this.config.getSmtpHost());
javaMailProperties.put(MAIL_PROP + protocol + ".port", this.config.getSmtpPort()+"");
javaMailProperties.put(MAIL_PROP + protocol + ".timeout", this.config.getTimeout()+"");
javaMailProperties.put(MAIL_PROP + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(this.config.getUsername())));
javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", Boolean.valueOf(this.config.isEnableTls()).toString());
return javaMailProperties;
}
}

16
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNodeConfiguration.java

@ -21,12 +21,24 @@ import org.thingsboard.rule.engine.api.NodeConfiguration;
@Data
public class TbSendEmailNodeConfiguration implements NodeConfiguration {
private String tmp;
private boolean useSystemSmtpSettings;
private String smtpHost;
private int smtpPort;
private String username;
private String password;
private String smtpProtocol;
private int timeout;
private boolean enableTls;
@Override
public TbSendEmailNodeConfiguration defaultConfiguration() {
TbSendEmailNodeConfiguration configuration = new TbSendEmailNodeConfiguration();
configuration.tmp = "";
configuration.setUseSystemSmtpSettings(true);
configuration.setSmtpHost("localhost");
configuration.setSmtpProtocol("smtp");
configuration.setSmtpPort(25);
configuration.setTimeout(10000);
configuration.setEnableTls(false);
return configuration;
}
}

6
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