You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/04/19 06:09:34 UTC
[logging-log4j2] branch release-2.x updated: [LOG4J2-3362] Adds a SmtpManager compatible with Jakarta EE 9
This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/release-2.x by this push:
new 30e9563fdb [LOG4J2-3362] Adds a SmtpManager compatible with Jakarta EE 9
30e9563fdb is described below
commit 30e9563fdb358bfbc334e6b86d3781fc7b281d74
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Tue Mar 29 22:54:20 2022 +0200
[LOG4J2-3362] Adds a SmtpManager compatible with Jakarta EE 9
Since javax.mail and jakarta.mail use different package names, as single
SmtpAppender can use both through different managers.
Unfortunately the implementations com.sun.mail:javax.mail and
com.sun.mail:jakarta.mail use the same class names, so it is not
possible to test both implementations at the same time. A separate test
execution was configured for the tests using jakarta.* classes.
---
log4j-core/pom.xml | 10 +
.../logging/log4j/core/appender/SmtpAppender.java | 68 ++++---
.../apache/logging/log4j/core/net/MailManager.java | 211 +++++++++++++++++++++
.../logging/log4j/core/net/MailManagerFactory.java | 26 +++
.../apache/logging/log4j/core/net/SmtpManager.java | 165 ++++------------
.../log4j/core/appender/SmtpAppenderTest.java | 15 +-
.../logging/log4j/core/net/SmtpManagerTest.java | 33 +++-
log4j-jakarta-smtp/pom.xml | 194 +++++++++++++++++++
.../logging/log4j/smtp/MimeMessageBuilder.java | 93 +++++++++
.../apache/logging/log4j/smtp}/SmtpManager.java | 202 ++++----------------
...pache.logging.log4j.core.net.MailManagerFactory | 1 +
.../logging/log4j/smtp/SmtpAppenderAsyncTest.java | 98 ++++++++++
.../logging/log4j/smtp}/SmtpAppenderTest.java | 24 ++-
.../logging/log4j/smtp}/SmtpManagerTest.java | 44 +++--
.../src/test/resources/SmtpAppenderAsyncTest.xml | 42 ++++
pom.xml | 40 +++-
16 files changed, 913 insertions(+), 353 deletions(-)
diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml
index 304eaf3c30..f21e19afa5 100644
--- a/log4j-core/pom.xml
+++ b/log4j-core/pom.xml
@@ -101,6 +101,16 @@
<optional>true</optional>
</dependency>
<!-- Required for SMTPAppender -->
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>javax.mail-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>javax.activation</groupId>
+ <artifactId>javax.activation-api</artifactId>
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
index 7b0ed6cb89..09c6f60f76 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
@@ -18,6 +18,7 @@
package org.apache.logging.log4j.core.appender;
import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
@@ -36,11 +37,18 @@ import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
import org.apache.logging.log4j.core.filter.ThresholdFilter;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer;
import org.apache.logging.log4j.core.layout.HtmlLayout;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.net.MailManager;
+import org.apache.logging.log4j.core.net.MailManager.FactoryData;
+import org.apache.logging.log4j.core.net.MailManagerFactory;
import org.apache.logging.log4j.core.net.SmtpManager;
import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.util.Booleans;
import org.apache.logging.log4j.core.util.Integers;
+import org.apache.logging.log4j.util.ServiceLoaderUtil;
+import org.apache.logging.log4j.util.Strings;
/**
* Send an e-mail when a specific logging event occurs, typically on errors or
@@ -66,14 +74,18 @@ public final class SmtpAppender extends AbstractAppender {
private static final int DEFAULT_BUFFER_SIZE = 512;
/** The SMTP Manager */
- private final SmtpManager manager;
+ private final MailManager manager;
private SmtpAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout,
- final SmtpManager manager, final boolean ignoreExceptions, final Property[] properties) {
+ final MailManager manager, final boolean ignoreExceptions, final Property[] properties) {
super(name, filter, layout, ignoreExceptions, properties);
this.manager = manager;
}
+ public MailManager getManager() {
+ return manager;
+ }
+
/**
* @since 2.13.2
*/
@@ -261,9 +273,25 @@ public final class SmtpAppender extends AbstractAppender {
if (getFilter() == null) {
setFilter(ThresholdFilter.createFilter(null, null, null));
}
- final SmtpManager smtpManager = SmtpManager.getSmtpManager(getConfiguration(), to, cc, bcc, from, replyTo,
- subject, smtpProtocol, smtpHost, smtpPort, smtpUsername, smtpPassword, smtpDebug,
- getFilter().toString(), bufferSize, sslConfiguration);
+ if (Strings.isEmpty(smtpProtocol)) {
+ smtpProtocol = "smtp";
+ }
+ final Serializer subjectSerializer = PatternLayout.newSerializerBuilder()
+ .setConfiguration(getConfiguration())
+ .setPattern(subject)
+ .build();
+ final FactoryData data = new FactoryData(to, cc, bcc, from, replyTo, subject, subjectSerializer,
+ smtpProtocol, smtpHost, smtpPort, smtpUsername, smtpPassword, smtpDebug, bufferSize,
+ sslConfiguration, getFilter().toString());
+ final MailManagerFactory factory = ServiceLoaderUtil.loadServices(MailManagerFactory.class, MethodHandles.lookup())
+ .findAny()
+ .orElseGet(() -> SmtpManager.FACTORY);
+ final MailManager smtpManager = AbstractManager.getManager(data.getManagerName(), factory, data);
+ if (smtpManager == null) {
+ LOGGER.error("Unabled to instantiate SmtpAppender named {}", getName());
+ return null;
+ }
+
return new SmtpAppender(getName(), getFilter(), getLayout(), smtpManager, isIgnoreExceptions(), getPropertyArray());
}
}
@@ -305,27 +333,15 @@ public final class SmtpAppender extends AbstractAppender {
LOGGER.error("No name provided for SmtpAppender");
return null;
}
-
- final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
- final int smtpPort = AbstractAppender.parseInt(smtpPortStr, 0);
- final boolean isSmtpDebug = Boolean.parseBoolean(smtpDebug);
- final int bufferSize = bufferSizeStr == null ? DEFAULT_BUFFER_SIZE : Integers.parseInt(bufferSizeStr);
-
- if (layout == null) {
- layout = HtmlLayout.createDefaultLayout();
- }
- if (filter == null) {
- filter = ThresholdFilter.createFilter(null, null, null);
- }
- final Configuration configuration = config != null ? config : new DefaultConfiguration();
-
- final SmtpManager manager = SmtpManager.getSmtpManager(configuration, to, cc, bcc, from, replyTo, subject, smtpProtocol,
- smtpHost, smtpPort, smtpUsername, smtpPassword, isSmtpDebug, filter.toString(), bufferSize, null);
- if (manager == null) {
- return null;
- }
-
- return new SmtpAppender(name, filter, layout, manager, ignoreExceptions, null);
+ return SmtpAppender.newBuilder()
+ .setIgnoreExceptions(Booleans.parseBoolean(ignore, true))
+ .setSmtpPort(AbstractAppender.parseInt(smtpPortStr, 0))
+ .setSmtpDebug(Boolean.parseBoolean(smtpDebug))
+ .setBufferSize(bufferSizeStr == null ? DEFAULT_BUFFER_SIZE : Integers.parseInt(bufferSizeStr))
+ .setLayout(layout)
+ .setFilter(filter)
+ .setConfiguration(config != null ? config : new DefaultConfiguration())
+ .build();
}
/**
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MailManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MailManager.java
new file mode 100644
index 0000000000..f8f07e346a
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MailManager.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.logging.log4j.core.net;
+
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractManager;
+import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer;
+import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
+
+/**
+ * Parent of all managers that send e-mails.
+ *
+ */
+public abstract class MailManager extends AbstractManager {
+
+ /**
+ * Creates a unique-per-configuration name for an smtp manager using the
+ * specified the parameters.<br>
+ * Using such a name allows us to maintain singletons per unique configurations.
+ *
+ * @return smtp manager name
+ */
+ static String createManagerName(final String to, final String cc, final String bcc, final String from,
+ final String replyTo, final String subject, final String smtpProtocol, final String smtpHost,
+ final int smtpPort, final String smtpUsername, final boolean smtpDebug, final String filterName) {
+
+ final StringBuilder sb = new StringBuilder();
+
+ if (to != null) {
+ sb.append(to);
+ }
+ sb.append(':');
+ if (cc != null) {
+ sb.append(cc);
+ }
+ sb.append(':');
+ if (bcc != null) {
+ sb.append(bcc);
+ }
+ sb.append(':');
+ if (from != null) {
+ sb.append(from);
+ }
+ sb.append(':');
+ if (replyTo != null) {
+ sb.append(replyTo);
+ }
+ sb.append(':');
+ if (subject != null) {
+ sb.append(subject);
+ }
+ sb.append(':');
+ sb.append(smtpProtocol).append(':').append(smtpHost).append(':').append(smtpPort).append(':');
+ if (smtpUsername != null) {
+ sb.append(smtpUsername);
+ }
+ sb.append(smtpDebug ? ":debug:" : "::");
+ sb.append(filterName);
+
+ return "SMTP:" + sb.toString();
+ }
+
+ public static class FactoryData {
+ private final String to;
+ private final String cc;
+ private final String bcc;
+ private final String from;
+ private final String replyTo;
+ private final String subject;
+ private final Serializer subjectSerializer;
+ private final String smtpProtocol;
+ private final String smtpHost;
+ private final int smtpPort;
+ private final String smtpUsername;
+ private final String smtpPassword;
+ private final boolean smtpDebug;
+ private final int bufferSize;
+ private final SslConfiguration sslConfiguration;
+ private final String filterName;
+ private final String managerName;
+
+
+
+ public FactoryData(String to, String cc, String bcc, String from, String replyTo, String subject,
+ Serializer subjectSerializer, String smtpProtocol, String smtpHost, int smtpPort, String smtpUsername,
+ String smtpPassword, boolean smtpDebug, int bufferSize, SslConfiguration sslConfiguration,
+ String filterName) {
+ this.to = to;
+ this.cc = cc;
+ this.bcc = bcc;
+ this.from = from;
+ this.replyTo = replyTo;
+ this.subject = subject;
+ this.subjectSerializer = subjectSerializer;
+ this.smtpProtocol = smtpProtocol;
+ this.smtpHost = smtpHost;
+ this.smtpPort = smtpPort;
+ this.smtpUsername = smtpUsername;
+ this.smtpPassword = smtpPassword;
+ this.smtpDebug = smtpDebug;
+ this.bufferSize = bufferSize;
+ this.sslConfiguration = sslConfiguration;
+ this.filterName = filterName;
+ this.managerName = createManagerName(to, cc, bcc, from, replyTo, subject, smtpProtocol, smtpHost, smtpPort,
+ smtpUsername, smtpDebug, filterName);
+ }
+
+ public String getTo() {
+ return to;
+ }
+
+ public String getCc() {
+ return cc;
+ }
+
+ public String getBcc() {
+ return bcc;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public String getReplyTo() {
+ return replyTo;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public Serializer getSubjectSerializer() {
+ return subjectSerializer;
+ }
+
+ public String getSmtpProtocol() {
+ return smtpProtocol;
+ }
+
+ public String getSmtpHost() {
+ return smtpHost;
+ }
+
+ public int getSmtpPort() {
+ return smtpPort;
+ }
+
+ public String getSmtpUsername() {
+ return smtpUsername;
+ }
+
+ public String getSmtpPassword() {
+ return smtpPassword;
+ }
+
+ public boolean isSmtpDebug() {
+ return smtpDebug;
+ }
+
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+ public SslConfiguration getSslConfiguration() {
+ return sslConfiguration;
+ }
+
+ public String getFilterName() {
+ return filterName;
+ }
+
+ public String getManagerName() {
+ return managerName;
+ }
+ }
+
+ public MailManager(LoggerContext loggerContext, String name) {
+ super(loggerContext, name);
+ }
+
+ /**
+ * Adds an event to the cyclic buffer.
+ *
+ * @param event The event to add.
+ */
+ public abstract void add(LogEvent event);
+
+ /**
+ * Send the contents of the cyclic buffer as an e-mail message.
+ *
+ * @param layout The layout for formatting the events.
+ * @param appendEvent The event that triggered the send.
+ */
+ public abstract void sendEvents(final Layout<?> layout, final LogEvent appendEvent);
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MailManagerFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MailManagerFactory.java
new file mode 100644
index 0000000000..9ef2b500d3
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/MailManagerFactory.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.logging.log4j.core.net;
+
+import org.apache.logging.log4j.core.appender.ManagerFactory;
+import org.apache.logging.log4j.core.net.MailManager.FactoryData;
+
+public interface MailManagerFactory extends ManagerFactory<MailManager, FactoryData> {
+
+ @Override
+ MailManager createManager(String name, FactoryData data);
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
index af16c9acb8..7e89f9d481 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
@@ -40,8 +40,6 @@ import javax.net.ssl.SSLSocketFactory;
import org.apache.logging.log4j.LoggingException;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer;
import org.apache.logging.log4j.core.layout.PatternLayout;
@@ -49,13 +47,12 @@ import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.util.CyclicBuffer;
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.Strings;
/**
* Manager for sending SMTP events.
*/
-public class SmtpManager extends AbstractManager {
- private static final SMTPManagerFactory FACTORY = new SMTPManagerFactory();
+public class SmtpManager extends MailManager {
+ public static final SMTPManagerFactory FACTORY = new SMTPManagerFactory();
private final Session session;
@@ -67,9 +64,12 @@ public class SmtpManager extends AbstractManager {
private static MimeMessage createMimeMessage(final FactoryData data, final Session session, final LogEvent appendEvent)
throws MessagingException {
- return new MimeMessageBuilder(session).setFrom(data.from).setReplyTo(data.replyto)
- .setRecipients(Message.RecipientType.TO, data.to).setRecipients(Message.RecipientType.CC, data.cc)
- .setRecipients(Message.RecipientType.BCC, data.bcc).setSubject(data.subject.toSerializable(appendEvent))
+ return new MimeMessageBuilder(session).setFrom(data.getFrom())
+ .setReplyTo(data.getReplyTo())
+ .setRecipients(Message.RecipientType.TO, data.getTo())
+ .setRecipients(Message.RecipientType.CC, data.getCc())
+ .setRecipients(Message.RecipientType.BCC, data.getBcc())
+ .setSubject(data.getSubjectSerializer().toSerializable(appendEvent))
.build();
}
@@ -79,13 +79,15 @@ public class SmtpManager extends AbstractManager {
this.session = session;
this.message = message;
this.data = data;
- this.buffer = new CyclicBuffer<>(LogEvent.class, data.numElements);
+ this.buffer = new CyclicBuffer<>(LogEvent.class, data.getBufferSize());
}
+ @Override
public void add(LogEvent event) {
buffer.add(event.toImmutable());
}
+ @Deprecated
public static SmtpManager getSmtpManager(
final Configuration config,
final String to, final String cc, final String bcc,
@@ -94,79 +96,18 @@ public class SmtpManager extends AbstractManager {
final int port, final String username, final String password,
final boolean isDebug, final String filterName, final int numElements,
final SslConfiguration sslConfiguration) {
- if (Strings.isEmpty(protocol)) {
- protocol = "smtp";
- }
-
- final String name = createManagerName(to, cc, bcc, from, replyTo, subject, protocol, host, port, username, isDebug, filterName);
- final Serializer subjectSerializer = PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(subject).build();
+ final Serializer subjectSerializer = PatternLayout.newSerializerBuilder()
+ .setConfiguration(config)
+ .setPattern(subject)
+ .build();
+ final FactoryData data = new FactoryData(to, cc, bcc, from, replyTo, subject, subjectSerializer, protocol, host,
+ port, username, password, isDebug, numElements, sslConfiguration, filterName);
- return getManager(name, FACTORY, new FactoryData(to, cc, bcc, from, replyTo, subjectSerializer,
- protocol, host, port, username, password, isDebug, numElements, sslConfiguration));
+ return (SmtpManager) getManager(data.getManagerName(), FACTORY, data);
}
- /**
- * Creates a unique-per-configuration name for an smtp manager using the specified the parameters.<br>
- * Using such a name allows us to maintain singletons per unique configurations.
- *
- * @return smtp manager name
- */
- static String createManagerName(
- final String to,
- final String cc,
- final String bcc,
- final String from,
- final String replyTo,
- final String subject,
- final String protocol,
- final String host,
- final int port,
- final String username,
- final boolean isDebug,
- final String filterName) {
-
- final StringBuilder sb = new StringBuilder();
-
- if (to != null) {
- sb.append(to);
- }
- sb.append(':');
- if (cc != null) {
- sb.append(cc);
- }
- sb.append(':');
- if (bcc != null) {
- sb.append(bcc);
- }
- sb.append(':');
- if (from != null) {
- sb.append(from);
- }
- sb.append(':');
- if (replyTo != null) {
- sb.append(replyTo);
- }
- sb.append(':');
- if (subject != null) {
- sb.append(subject);
- }
- sb.append(':');
- sb.append(protocol).append(':').append(host).append(':').append(port).append(':');
- if (username != null) {
- sb.append(username);
- }
- sb.append(isDebug ? ":debug:" : "::");
- sb.append(filterName);
-
- return "SMTP:" + sb.toString();
- }
-
- /**
- * Send the contents of the cyclic buffer as an e-mail message.
- * @param layout The layout for formatting the events.
- * @param appendEvent The event that triggered the send.
- */
+ @Override
public void sendEvents(final Layout<?> layout, final LogEvent appendEvent) {
if (message == null) {
connect(appendEvent);
@@ -184,7 +125,7 @@ public class SmtpManager extends AbstractManager {
final InternetHeaders headers = getHeaders(contentType, encoding);
final MimeMultipart mp = getMimeMultipart(encodedBytes, headers);
- final String subject = data.subject.toSerializable(appendEvent);
+ final String subject = data.getSubjectSerializer().toSerializable(appendEvent);
sendMultipartMessage(message, mp, subject);
} catch (final MessagingException | IOException | RuntimeException e) {
@@ -292,46 +233,6 @@ public class SmtpManager extends AbstractManager {
}
}
- /**
- * Factory data.
- */
- private static class FactoryData {
- private final String to;
- private final String cc;
- private final String bcc;
- private final String from;
- private final String replyto;
- private final Serializer subject;
- private final String protocol;
- private final String host;
- private final int port;
- private final String username;
- private final String password;
- private final boolean isDebug;
- private final int numElements;
- private final SslConfiguration sslConfiguration;
-
- public FactoryData(final String to, final String cc, final String bcc, final String from, final String replyTo,
- final Serializer subjectSerializer, final String protocol, final String host, final int port,
- final String username, final String password, final boolean isDebug, final int numElements,
- final SslConfiguration sslConfiguration) {
- this.to = to;
- this.cc = cc;
- this.bcc = bcc;
- this.from = from;
- this.replyto = replyTo;
- this.subject = subjectSerializer;
- this.protocol = protocol;
- this.host = host;
- this.port = port;
- this.username = username;
- this.password = password;
- this.isDebug = isDebug;
- this.numElements = numElements;
- this.sslConfiguration = sslConfiguration;
- }
- }
-
private synchronized void connect(final LogEvent appendEvent) {
if (message != null) {
return;
@@ -347,33 +248,35 @@ public class SmtpManager extends AbstractManager {
/**
* Factory to create the SMTP Manager.
*/
- private static class SMTPManagerFactory implements ManagerFactory<SmtpManager, FactoryData> {
+ public static class SMTPManagerFactory implements MailManagerFactory {
@Override
public SmtpManager createManager(final String name, final FactoryData data) {
- final String prefix = "mail." + data.protocol;
+ final String smtpProtocol = data.getSmtpProtocol();
+ final String prefix = "mail." + smtpProtocol;
final Properties properties = PropertiesUtil.getSystemProperties();
- properties.setProperty("mail.transport.protocol", data.protocol);
+ properties.setProperty("mail.transport.protocol", smtpProtocol);
if (properties.getProperty("mail.host") == null) {
// Prevent an UnknownHostException in Java 7
properties.setProperty("mail.host", NetUtils.getLocalHostname());
}
- if (null != data.host) {
- properties.setProperty(prefix + ".host", data.host);
+ final String smtpHost = data.getSmtpHost();
+ if (null != smtpHost) {
+ properties.setProperty(prefix + ".host", smtpHost);
}
- if (data.port > 0) {
- properties.setProperty(prefix + ".port", String.valueOf(data.port));
+ if (data.getSmtpPort() > 0) {
+ properties.setProperty(prefix + ".port", String.valueOf(data.getSmtpPort()));
}
- final Authenticator authenticator = buildAuthenticator(data.username, data.password);
+ final Authenticator authenticator = buildAuthenticator(data.getSmtpUsername(), data.getSmtpPassword());
if (null != authenticator) {
properties.setProperty(prefix + ".auth", "true");
}
- if (data.protocol.equals("smtps")) {
- final SslConfiguration sslConfiguration = data.sslConfiguration;
+ if (smtpProtocol.equals("smtps")) {
+ final SslConfiguration sslConfiguration = data.getSslConfiguration();
if (sslConfiguration != null) {
final SSLSocketFactory sslSocketFactory = sslConfiguration.getSslSocketFactory();
properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
@@ -382,8 +285,8 @@ public class SmtpManager extends AbstractManager {
}
final Session session = Session.getInstance(properties, authenticator);
- session.setProtocolForAddress("rfc822", data.protocol);
- session.setDebug(data.isDebug);
+ session.setProtocolForAddress("rfc822", smtpProtocol);
+ session.setDebug(data.isSmtpDebug());
return new SmtpManager(name, session, null, data);
}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
index 2a4cf4cf7a..d0cf61afcf 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
@@ -16,7 +16,15 @@
*/
package org.apache.logging.log4j.core.appender;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
import java.util.Iterator;
+
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
@@ -30,12 +38,11 @@ import org.apache.logging.log4j.categories.Appenders;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.net.MimeMessageBuilder;
+import org.apache.logging.log4j.core.net.SmtpManager;
import org.apache.logging.log4j.test.AvailablePortFinder;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import static org.junit.Assert.*;
-
@Category(Appenders.Smtp.class)
public class SmtpAppenderTest {
@@ -125,6 +132,8 @@ public class SmtpAppenderTest {
.setSmtpPort(smtpPort)
.setBufferSize(3)
.build();
+ assertNotNull(appender);
+ assertTrue(appender.getManager() instanceof SmtpManager);
appender.start();
final LoggerContext context = LoggerContext.getContext();
@@ -174,4 +183,6 @@ public class SmtpAppenderTest {
assertFalse(body2.contains("Error with exception"));
assertTrue(body2.contains("Error message #2"));
}
+
+
}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java
index 5759cf7bbb..224369068d 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java
@@ -23,6 +23,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.SmtpAppender;
import org.apache.logging.log4j.core.async.RingBufferLogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.MementoMessage;
@@ -33,20 +34,36 @@ import org.apache.logging.log4j.message.ReusableMessage;
import org.apache.logging.log4j.message.ReusableSimpleMessage;
import org.junit.jupiter.api.Test;
-/**
- * Unit tests for {@link SmtpManager}.
- */
public class SmtpManagerTest {
@Test
- void testCreateManagerName() {
+ public void testCreateManagerName() {
String managerName = SmtpManager.createManagerName("to", "cc", null, "from", null, "LOG4J2-3107",
"proto", "smtp.log4j.com", 4711, "username", false, "filter");
assertEquals("SMTP:to:cc::from::LOG4J2-3107:proto:smtp.log4j.com:4711:username::filter", managerName);
}
private void testAdd(LogEvent event) {
- SmtpManager smtpManager = SmtpManager.getSmtpManager(null, "to", "cc", "bcc", "from", "replyTo", "subject", "protocol", "host", 0, "username", "password", false, "filterName", 10, null);
+ final SmtpAppender appender = SmtpAppender.newBuilder()
+ .setName("smtp")
+ .setTo("to")
+ .setCc("cc")
+ .setBcc("bcc")
+ .setFrom("from")
+ .setReplyTo("replyTo")
+ .setSubject("subject")
+ .setSmtpProtocol("smtp")
+ .setSmtpHost("host")
+ .setSmtpPort(0)
+ .setSmtpUsername("username")
+ .setSmtpPassword("password")
+ .setSmtpDebug(false)
+ .setFilter(null)
+ .setBufferSize(10)
+ .build();
+ final MailManager mailManager = appender.getManager();
+ assertThat("is instance of SmtpManager", mailManager instanceof SmtpManager);
+ final SmtpManager smtpManager = (SmtpManager) mailManager;
smtpManager.removeAllBufferedEvents(); // in case this smtpManager is reused
smtpManager.add(event);
@@ -57,21 +74,21 @@ public class SmtpManagerTest {
// LOG4J2-3172: make sure existing protections are not violated
@Test
- void testAdd_WhereLog4jLogEventWithReusableMessage() {
+ public void testAdd_WhereLog4jLogEventWithReusableMessage() {
LogEvent event = new Log4jLogEvent.Builder().setMessage(getReusableMessage("test message")).build();
testAdd(event);
}
// LOG4J2-3172: make sure existing protections are not violated
@Test
- void testAdd_WhereMutableLogEvent() {
+ public void testAdd_WhereMutableLogEvent() {
MutableLogEvent event = new MutableLogEvent(new StringBuilder("test message"), null);
testAdd(event);
}
// LOG4J2-3172
@Test
- void testAdd_WhereRingBufferLogEvent() {
+ public void testAdd_WhereRingBufferLogEvent() {
RingBufferLogEvent event = new RingBufferLogEvent();
event.setValues(null, null, null, null, null, getReusableMessage("test message"), null, null, null, 0, null, 0, null, ClockFactory.getClock(), new DummyNanoClock());
testAdd(event);
diff --git a/log4j-jakarta-smtp/pom.xml b/log4j-jakarta-smtp/pom.xml
new file mode 100644
index 0000000000..a1c8cfd0df
--- /dev/null
+++ b/log4j-jakarta-smtp/pom.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>2.17.3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>log4j-smtp</artifactId>
+ <name>Apache Log4j SMTP</name>
+ <description>
+ Apache Log4j Simple Mail Transfer Protocol (SMTP) Appender, version for Jakarta EE 9.
+ </description>
+ <properties>
+ <log4jParentDir>${basedir}/..</log4jParentDir>
+ <docLabel>Log4j SMTP Appender Documentation</docLabel>
+ <projectDir>/log4j-jakarta-smtp</projectDir>
+ <maven.doap.skip>true</maven.doap.skip>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ </dependency>
+ <!-- Required for SMTPAppender -->
+ <dependency>
+ <groupId>jakarta.activation</groupId>
+ <artifactId>jakarta.activation-api</artifactId>
+ <!-- the implementation jar contains the API -->
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.activation</groupId>
+ <artifactId>jakarta.activation</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.mail</groupId>
+ <artifactId>jakarta.mail-api</artifactId>
+ <!-- the implementation jar contains the API -->
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>smtp</artifactId>
+ </dependency>
+ <!-- Test Dependencies -->
+ <dependency>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>com.lmax</groupId>
+ <artifactId>disruptor</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Fragment-Host>org.apache.logging.log4j.core.appender.mom.jeromq</Fragment-Host>
+ <Export-Package>*</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>${changes.plugin.version}</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ <configuration>
+ <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+ <useJql>true</useJql>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>${checkstyle.plugin.version}</version>
+ <configuration>
+ <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation> -->
+ <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
+ <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
+ <enableRulesSummary>false</enableRulesSummary>
+ <propertyExpansion>basedir=${basedir}</propertyExpansion>
+ <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>${javadoc.plugin.version}</version>
+ <configuration>
+ <bottom><![CDATA[<p align="center">Copyright © {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
+ Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, the Apache Logging project logo,
+ and the Apache Log4j logo are trademarks of The Apache Software Foundation.</p>]]></bottom>
+ <!-- module link generation is completely broken in the javadoc plugin for a multi-module non-aggregating project -->
+ <detectOfflineLinks>false</detectOfflineLinks>
+ <linksource>true</linksource>
+ <source>8</source>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <id>non-aggregate</id>
+ <reports>
+ <report>javadoc</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jxr-plugin</artifactId>
+ <version>${jxr.plugin.version}</version>
+ <reportSets>
+ <reportSet>
+ <id>non-aggregate</id>
+ <reports>
+ <report>jxr</report>
+ </reports>
+ </reportSet>
+ <reportSet>
+ <id>aggregate</id>
+ <reports>
+ <report>aggregate</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-pmd-plugin</artifactId>
+ <version>${pmd.plugin.version}</version>
+ <configuration>
+ <targetJdk>${maven.compiler.target}</targetJdk>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
\ No newline at end of file
diff --git a/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/MimeMessageBuilder.java b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/MimeMessageBuilder.java
new file mode 100644
index 0000000000..4e99326a9b
--- /dev/null
+++ b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/MimeMessageBuilder.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.logging.log4j.smtp;
+
+import java.nio.charset.StandardCharsets;
+
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.Session;
+import jakarta.mail.internet.AddressException;
+import jakarta.mail.internet.InternetAddress;
+import jakarta.mail.internet.MimeMessage;
+
+import org.apache.logging.log4j.core.util.Builder;
+
+/**
+ * Builder for {@link MimeMessage} instances.
+ */
+public class MimeMessageBuilder implements Builder<MimeMessage> {
+ private final MimeMessage message;
+
+ public MimeMessageBuilder(final Session session) {
+ message = new MimeMessage(session);
+ }
+
+ public MimeMessageBuilder setFrom(final String from) throws MessagingException {
+ final InternetAddress address = parseAddress(from);
+
+ if (null != address) {
+ message.setFrom(address);
+ } else {
+ try {
+ message.setFrom();
+ } catch (final Exception ex) {
+ message.setFrom((InternetAddress) null);
+ }
+ }
+ return this;
+ }
+
+ public MimeMessageBuilder setReplyTo(final String replyTo) throws MessagingException {
+ final InternetAddress[] addresses = parseAddresses(replyTo);
+
+ if (null != addresses) {
+ message.setReplyTo(addresses);
+ }
+ return this;
+ }
+
+ public MimeMessageBuilder setRecipients(final Message.RecipientType recipientType, final String recipients)
+ throws MessagingException {
+ final InternetAddress[] addresses = parseAddresses(recipients);
+
+ if (null != addresses) {
+ message.setRecipients(recipientType, addresses);
+ }
+ return this;
+ }
+
+ public MimeMessageBuilder setSubject(final String subject) throws MessagingException {
+ if (subject != null) {
+ message.setSubject(subject, StandardCharsets.UTF_8.name());
+ }
+ return this;
+ }
+
+ @Override
+ public MimeMessage build() {
+ return message;
+ }
+
+ private static InternetAddress parseAddress(final String address) throws AddressException {
+ return address == null ? null : new InternetAddress(address);
+ }
+
+ private static InternetAddress[] parseAddresses(final String addresses) throws AddressException {
+ return addresses == null ? null : InternetAddress.parse(addresses, true);
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
similarity index 58%
copy from log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
copy to log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
index af16c9acb8..4c838b5b8f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/SmtpManager.java
+++ b/log4j-jakarta-smtp/src/main/java/org/apache/logging/log4j/smtp/SmtpManager.java
@@ -14,7 +14,7 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-package org.apache.logging.log4j.core.net;
+package org.apache.logging.log4j.smtp;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -22,40 +22,36 @@ import java.io.OutputStream;
import java.util.Date;
import java.util.Properties;
-import javax.activation.DataSource;
-import javax.mail.Authenticator;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.PasswordAuthentication;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetHeaders;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import javax.mail.internet.MimeUtility;
-import javax.mail.util.ByteArrayDataSource;
import javax.net.ssl.SSLSocketFactory;
+import jakarta.activation.DataSource;
+import jakarta.mail.Authenticator;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.PasswordAuthentication;
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import jakarta.mail.internet.InternetHeaders;
+import jakarta.mail.internet.MimeBodyPart;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.internet.MimeMultipart;
+import jakarta.mail.internet.MimeUtility;
+import jakarta.mail.util.ByteArrayDataSource;
+
import org.apache.logging.log4j.LoggingException;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.appender.AbstractManager;
-import org.apache.logging.log4j.core.appender.ManagerFactory;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.layout.AbstractStringLayout.Serializer;
-import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.net.MailManager;
+import org.apache.logging.log4j.core.net.MailManagerFactory;
import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
import org.apache.logging.log4j.core.util.CyclicBuffer;
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.Strings;
/**
* Manager for sending SMTP events.
*/
-public class SmtpManager extends AbstractManager {
- private static final SMTPManagerFactory FACTORY = new SMTPManagerFactory();
+public class SmtpManager extends MailManager {
private final Session session;
@@ -67,9 +63,12 @@ public class SmtpManager extends AbstractManager {
private static MimeMessage createMimeMessage(final FactoryData data, final Session session, final LogEvent appendEvent)
throws MessagingException {
- return new MimeMessageBuilder(session).setFrom(data.from).setReplyTo(data.replyto)
- .setRecipients(Message.RecipientType.TO, data.to).setRecipients(Message.RecipientType.CC, data.cc)
- .setRecipients(Message.RecipientType.BCC, data.bcc).setSubject(data.subject.toSerializable(appendEvent))
+ return new MimeMessageBuilder(session).setFrom(data.getFrom())
+ .setReplyTo(data.getReplyTo())
+ .setRecipients(Message.RecipientType.TO, data.getTo())
+ .setRecipients(Message.RecipientType.CC, data.getCc())
+ .setRecipients(Message.RecipientType.BCC, data.getBcc())
+ .setSubject(data.getSubjectSerializer().toSerializable(appendEvent))
.build();
}
@@ -79,94 +78,15 @@ public class SmtpManager extends AbstractManager {
this.session = session;
this.message = message;
this.data = data;
- this.buffer = new CyclicBuffer<>(LogEvent.class, data.numElements);
+ this.buffer = new CyclicBuffer<>(LogEvent.class, data.getBufferSize());
}
+ @Override
public void add(LogEvent event) {
buffer.add(event.toImmutable());
}
- public static SmtpManager getSmtpManager(
- final Configuration config,
- final String to, final String cc, final String bcc,
- final String from, final String replyTo,
- final String subject, String protocol, final String host,
- final int port, final String username, final String password,
- final boolean isDebug, final String filterName, final int numElements,
- final SslConfiguration sslConfiguration) {
- if (Strings.isEmpty(protocol)) {
- protocol = "smtp";
- }
-
- final String name = createManagerName(to, cc, bcc, from, replyTo, subject, protocol, host, port, username, isDebug, filterName);
- final Serializer subjectSerializer = PatternLayout.newSerializerBuilder().setConfiguration(config).setPattern(subject).build();
-
- return getManager(name, FACTORY, new FactoryData(to, cc, bcc, from, replyTo, subjectSerializer,
- protocol, host, port, username, password, isDebug, numElements, sslConfiguration));
-
- }
-
- /**
- * Creates a unique-per-configuration name for an smtp manager using the specified the parameters.<br>
- * Using such a name allows us to maintain singletons per unique configurations.
- *
- * @return smtp manager name
- */
- static String createManagerName(
- final String to,
- final String cc,
- final String bcc,
- final String from,
- final String replyTo,
- final String subject,
- final String protocol,
- final String host,
- final int port,
- final String username,
- final boolean isDebug,
- final String filterName) {
-
- final StringBuilder sb = new StringBuilder();
-
- if (to != null) {
- sb.append(to);
- }
- sb.append(':');
- if (cc != null) {
- sb.append(cc);
- }
- sb.append(':');
- if (bcc != null) {
- sb.append(bcc);
- }
- sb.append(':');
- if (from != null) {
- sb.append(from);
- }
- sb.append(':');
- if (replyTo != null) {
- sb.append(replyTo);
- }
- sb.append(':');
- if (subject != null) {
- sb.append(subject);
- }
- sb.append(':');
- sb.append(protocol).append(':').append(host).append(':').append(port).append(':');
- if (username != null) {
- sb.append(username);
- }
- sb.append(isDebug ? ":debug:" : "::");
- sb.append(filterName);
-
- return "SMTP:" + sb.toString();
- }
-
- /**
- * Send the contents of the cyclic buffer as an e-mail message.
- * @param layout The layout for formatting the events.
- * @param appendEvent The event that triggered the send.
- */
+ @Override
public void sendEvents(final Layout<?> layout, final LogEvent appendEvent) {
if (message == null) {
connect(appendEvent);
@@ -184,7 +104,7 @@ public class SmtpManager extends AbstractManager {
final InternetHeaders headers = getHeaders(contentType, encoding);
final MimeMultipart mp = getMimeMultipart(encodedBytes, headers);
- final String subject = data.subject.toSerializable(appendEvent);
+ final String subject = data.getSubjectSerializer().toSerializable(appendEvent);
sendMultipartMessage(message, mp, subject);
} catch (final MessagingException | IOException | RuntimeException e) {
@@ -292,46 +212,6 @@ public class SmtpManager extends AbstractManager {
}
}
- /**
- * Factory data.
- */
- private static class FactoryData {
- private final String to;
- private final String cc;
- private final String bcc;
- private final String from;
- private final String replyto;
- private final Serializer subject;
- private final String protocol;
- private final String host;
- private final int port;
- private final String username;
- private final String password;
- private final boolean isDebug;
- private final int numElements;
- private final SslConfiguration sslConfiguration;
-
- public FactoryData(final String to, final String cc, final String bcc, final String from, final String replyTo,
- final Serializer subjectSerializer, final String protocol, final String host, final int port,
- final String username, final String password, final boolean isDebug, final int numElements,
- final SslConfiguration sslConfiguration) {
- this.to = to;
- this.cc = cc;
- this.bcc = bcc;
- this.from = from;
- this.replyto = replyTo;
- this.subject = subjectSerializer;
- this.protocol = protocol;
- this.host = host;
- this.port = port;
- this.username = username;
- this.password = password;
- this.isDebug = isDebug;
- this.numElements = numElements;
- this.sslConfiguration = sslConfiguration;
- }
- }
-
private synchronized void connect(final LogEvent appendEvent) {
if (message != null) {
return;
@@ -347,33 +227,35 @@ public class SmtpManager extends AbstractManager {
/**
* Factory to create the SMTP Manager.
*/
- private static class SMTPManagerFactory implements ManagerFactory<SmtpManager, FactoryData> {
+ public static class SMTPManagerFactory implements MailManagerFactory {
@Override
public SmtpManager createManager(final String name, final FactoryData data) {
- final String prefix = "mail." + data.protocol;
+ final String smtpProtocol = data.getSmtpProtocol();
+ final String prefix = "mail." + smtpProtocol;
final Properties properties = PropertiesUtil.getSystemProperties();
- properties.setProperty("mail.transport.protocol", data.protocol);
+ properties.setProperty("mail.transport.protocol", smtpProtocol);
if (properties.getProperty("mail.host") == null) {
// Prevent an UnknownHostException in Java 7
properties.setProperty("mail.host", NetUtils.getLocalHostname());
}
- if (null != data.host) {
- properties.setProperty(prefix + ".host", data.host);
+ final String smtpHost = data.getSmtpHost();
+ if (null != smtpHost) {
+ properties.setProperty(prefix + ".host", smtpHost);
}
- if (data.port > 0) {
- properties.setProperty(prefix + ".port", String.valueOf(data.port));
+ if (data.getSmtpPort() > 0) {
+ properties.setProperty(prefix + ".port", String.valueOf(data.getSmtpPort()));
}
- final Authenticator authenticator = buildAuthenticator(data.username, data.password);
+ final Authenticator authenticator = buildAuthenticator(data.getSmtpUsername(), data.getSmtpPassword());
if (null != authenticator) {
properties.setProperty(prefix + ".auth", "true");
}
- if (data.protocol.equals("smtps")) {
- final SslConfiguration sslConfiguration = data.sslConfiguration;
+ if (smtpProtocol.equals("smtps")) {
+ final SslConfiguration sslConfiguration = data.getSslConfiguration();
if (sslConfiguration != null) {
final SSLSocketFactory sslSocketFactory = sslConfiguration.getSslSocketFactory();
properties.put(prefix + ".ssl.socketFactory", sslSocketFactory);
@@ -382,8 +264,8 @@ public class SmtpManager extends AbstractManager {
}
final Session session = Session.getInstance(properties, authenticator);
- session.setProtocolForAddress("rfc822", data.protocol);
- session.setDebug(data.isDebug);
+ session.setProtocolForAddress("rfc822", smtpProtocol);
+ session.setDebug(data.isSmtpDebug());
return new SmtpManager(name, session, null, data);
}
diff --git a/log4j-jakarta-smtp/src/main/resources/META-INF/services/org.apache.logging.log4j.core.net.MailManagerFactory b/log4j-jakarta-smtp/src/main/resources/META-INF/services/org.apache.logging.log4j.core.net.MailManagerFactory
new file mode 100644
index 0000000000..8b89a565e9
--- /dev/null
+++ b/log4j-jakarta-smtp/src/main/resources/META-INF/services/org.apache.logging.log4j.core.net.MailManagerFactory
@@ -0,0 +1 @@
+org.apache.logging.log4j.smtp.SmtpManager$SMTPManagerFactory
\ No newline at end of file
diff --git a/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpAppenderAsyncTest.java b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpAppenderAsyncTest.java
new file mode 100644
index 0000000000..3a18b26615
--- /dev/null
+++ b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpAppenderAsyncTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.logging.log4j.smtp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+
+import org.apache.logging.dumbster.smtp.SimpleSmtpServer;
+import org.apache.logging.dumbster.smtp.SmtpMessage;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.Logger;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.apache.logging.log4j.test.AvailablePortFinder;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class SmtpAppenderAsyncTest {
+
+ private static int PORT;
+
+ private SimpleSmtpServer smtpServer;
+
+ @BeforeClass
+ public static void setupClass() {
+ PORT = AvailablePortFinder.getNextAvailable();
+ System.setProperty("smtp.port", String.valueOf(PORT));
+ }
+
+ @Before
+ public void setup() {
+ smtpServer = SimpleSmtpServer.start(PORT);
+ }
+
+ @Rule
+ public LoggerContextRule ctx = new LoggerContextRule("SmtpAppenderAsyncTest.xml");
+
+ @Test
+ public void testSync() {
+ testSmtpAppender(ctx.getLogger("sync"));
+ }
+
+ @Test
+ public void testAsync() {
+ testSmtpAppender(ctx.getLogger("async"));
+ }
+
+ private void testSmtpAppender(final Logger logger) {
+ ThreadContext.put("MDC1", "mdc1");
+ logger.error("the message");
+ ctx.getLoggerContext().stop();
+ smtpServer.stop();
+
+ assertEquals(1, smtpServer.getReceivedEmailSize());
+ final Iterator<SmtpMessage> messages = smtpServer.getReceivedEmail();
+ final SmtpMessage email = messages.next();
+
+ assertEquals("to@example.com", email.getHeaderValue("To"));
+ assertEquals("from@example.com", email.getHeaderValue("From"));
+ assertEquals("[mdc1]", email.getHeaderValue("Subject"));
+
+ final String body = email.getBody();
+ if (!body.contains("Body:[mdc1]")) {
+ fail(body);
+ }
+ }
+
+ @After
+ public void teardown() {
+ if (smtpServer != null) {
+ smtpServer.stop();
+ }
+ }
+
+ @AfterClass
+ public static void teardownClass() {
+ System.clearProperty("smtp.port");
+ }
+}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpAppenderTest.java
similarity index 91%
copy from log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
copy to log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpAppenderTest.java
index 2a4cf4cf7a..8360c18cc5 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/SmtpAppenderTest.java
+++ b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpAppenderTest.java
@@ -14,13 +14,21 @@
* See the license for the specific language governing permissions and
* limitations under the license.
*/
-package org.apache.logging.log4j.core.appender;
+package org.apache.logging.log4j.smtp;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.util.Iterator;
-import javax.mail.Address;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.internet.InternetAddress;
+
+import jakarta.mail.Address;
+import jakarta.mail.Message;
+import jakarta.mail.MessagingException;
+import jakarta.mail.internet.InternetAddress;
import org.apache.logging.dumbster.smtp.SimpleSmtpServer;
import org.apache.logging.dumbster.smtp.SmtpMessage;
@@ -29,13 +37,11 @@ import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.categories.Appenders;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.net.MimeMessageBuilder;
+import org.apache.logging.log4j.core.appender.SmtpAppender;
import org.apache.logging.log4j.test.AvailablePortFinder;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import static org.junit.Assert.*;
-
@Category(Appenders.Smtp.class)
public class SmtpAppenderTest {
@@ -125,6 +131,8 @@ public class SmtpAppenderTest {
.setSmtpPort(smtpPort)
.setBufferSize(3)
.build();
+ assertNotNull(appender);
+ assertTrue(appender.getManager() instanceof SmtpManager);
appender.start();
final LoggerContext context = LoggerContext.getContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpManagerTest.java
similarity index 70%
copy from log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java
copy to log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpManagerTest.java
index 5759cf7bbb..1ddd7b01aa 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/SmtpManagerTest.java
+++ b/log4j-jakarta-smtp/src/test/java/org/apache/logging/log4j/smtp/SmtpManagerTest.java
@@ -15,38 +15,48 @@
* limitations under the license.
*/
-package org.apache.logging.log4j.core.net;
+package org.apache.logging.log4j.smtp;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.appender.SmtpAppender;
import org.apache.logging.log4j.core.async.RingBufferLogEvent;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.MementoMessage;
import org.apache.logging.log4j.core.impl.MutableLogEvent;
+import org.apache.logging.log4j.core.net.MailManager;
import org.apache.logging.log4j.core.util.ClockFactory;
import org.apache.logging.log4j.core.util.DummyNanoClock;
import org.apache.logging.log4j.message.ReusableMessage;
import org.apache.logging.log4j.message.ReusableSimpleMessage;
-import org.junit.jupiter.api.Test;
+import org.junit.Test;
-/**
- * Unit tests for {@link SmtpManager}.
- */
public class SmtpManagerTest {
- @Test
- void testCreateManagerName() {
- String managerName = SmtpManager.createManagerName("to", "cc", null, "from", null, "LOG4J2-3107",
- "proto", "smtp.log4j.com", 4711, "username", false, "filter");
- assertEquals("SMTP:to:cc::from::LOG4J2-3107:proto:smtp.log4j.com:4711:username::filter", managerName);
- }
-
private void testAdd(LogEvent event) {
- SmtpManager smtpManager = SmtpManager.getSmtpManager(null, "to", "cc", "bcc", "from", "replyTo", "subject", "protocol", "host", 0, "username", "password", false, "filterName", 10, null);
+ final SmtpAppender appender = SmtpAppender.newBuilder()
+ .setName("smtp")
+ .setTo("to")
+ .setCc("cc")
+ .setBcc("bcc")
+ .setFrom("from")
+ .setReplyTo("replyTo")
+ .setSubject("subject")
+ .setSmtpProtocol("smtp")
+ .setSmtpHost("host")
+ .setSmtpPort(0)
+ .setSmtpUsername("username")
+ .setSmtpPassword("password")
+ .setSmtpDebug(false)
+ .setFilter(null)
+ .setBufferSize(10)
+ .build();
+ final MailManager mailManager = appender.getManager();
+ assertThat("is instance of SmtpManager", mailManager instanceof SmtpManager);
+ final SmtpManager smtpManager = (SmtpManager) mailManager;
smtpManager.removeAllBufferedEvents(); // in case this smtpManager is reused
smtpManager.add(event);
@@ -57,21 +67,21 @@ public class SmtpManagerTest {
// LOG4J2-3172: make sure existing protections are not violated
@Test
- void testAdd_WhereLog4jLogEventWithReusableMessage() {
+ public void testAdd_WhereLog4jLogEventWithReusableMessage() {
LogEvent event = new Log4jLogEvent.Builder().setMessage(getReusableMessage("test message")).build();
testAdd(event);
}
// LOG4J2-3172: make sure existing protections are not violated
@Test
- void testAdd_WhereMutableLogEvent() {
+ public void testAdd_WhereMutableLogEvent() {
MutableLogEvent event = new MutableLogEvent(new StringBuilder("test message"), null);
testAdd(event);
}
// LOG4J2-3172
@Test
- void testAdd_WhereRingBufferLogEvent() {
+ public void testAdd_WhereRingBufferLogEvent() {
RingBufferLogEvent event = new RingBufferLogEvent();
event.setValues(null, null, null, null, null, getReusableMessage("test message"), null, null, null, 0, null, 0, null, ClockFactory.getClock(), new DummyNanoClock());
testAdd(event);
diff --git a/log4j-jakarta-smtp/src/test/resources/SmtpAppenderAsyncTest.xml b/log4j-jakarta-smtp/src/test/resources/SmtpAppenderAsyncTest.xml
new file mode 100644
index 0000000000..1939ddd2e9
--- /dev/null
+++ b/log4j-jakarta-smtp/src/test/resources/SmtpAppenderAsyncTest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You 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.
+ -->
+<Configuration name="SmtpAppenderAsyncTest" status="WARN">
+ <Appenders>
+ <SMTP name="mail-sync" to="to@example.com" from="from@example.com" smtpHost="localhost"
+ smtpPort="${sys:smtp.port}" ignoreExceptions="false" subject="[%X{MDC1}]">
+ <PatternLayout pattern="Body:[%X{MDC1}]" />
+ </SMTP>
+ <Async name="mail-async">
+ <AppenderRef ref="mail-sync"/>
+ </Async>
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable" />
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="FATAL">
+ <AppenderRef ref="Console"/>
+ </Root>
+ <Logger name="sync" level="INFO">
+ <AppenderRef ref="mail-sync"/>
+ </Logger>
+ <Logger name="async" level="INFO">
+ <AppenderRef ref="mail-async"/>
+ </Logger>
+ </Loggers>
+</Configuration>
diff --git a/pom.xml b/pom.xml
index f28e4717bb..6cc3ec117c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -303,6 +303,10 @@
<junitPioneerVersion>1.6.2</junitPioneerVersion>
<mockitoVersion>4.4.0</mockitoVersion>
<xmlunitVersion>2.9.0</xmlunitVersion>
+ <javax.activation.version>1.2.0</javax.activation.version>
+ <javax.mail.version>1.6.2</javax.mail.version>
+ <jakarta.activation.version>2.0.1</jakarta.activation.version>
+ <jakarta.mail.version>2.0.1</jakarta.mail.version>
<argLine>-Xms256m -Xmx1024m</argLine>
<javaTargetVersion>1.8</javaTargetVersion>
<module.name />
@@ -697,10 +701,43 @@
<optional>true</optional>
</dependency>
<!-- Jackson 2 end -->
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>javax.mail-api</artifactId>
+ <version>${javax.mail.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.activation</groupId>
+ <artifactId>javax.activation-api</artifactId>
+ <version>${javax.activation.version}</version>
+ </dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
- <version>1.6.2</version>
+ <version>${javax.mail.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.mail</groupId>
+ <artifactId>jakarta.mail-api</artifactId>
+ <version>${jakarta.mail.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>jakarta.activation</groupId>
+ <artifactId>jakarta.activation-api</artifactId>
+ <version>${jakarta.activation.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.mail</groupId>
+ <artifactId>smtp</artifactId>
+ <version>${jakarta.mail.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.activation</groupId>
+ <artifactId>jakarta.activation</artifactId>
+ <version>${jakarta.activation.version}</version>
+ <scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.jms</groupId>
@@ -1651,6 +1688,7 @@
<module>log4j-kubernetes</module>
<module>log4j-spring-boot</module>
<module>log4j-spring-cloud-config</module>
+ <module>log4j-jakarta-smtp</module>
</modules>
<profiles>
<profile>