Project: javamail
Repository: mercurial
Revision: 671
Author: shannon
Date: 2014-11-08 01:09:06 UTC
Link:
Log Message:
------------
Add missing serialVersionUID.
Remove unused Executor field.
Improve debug output.
Allow any non-SSL protocol, not just TLSv1.
Update logging demos to use the new 1.5.2 features - bug 6551
(From Jason)
Include logging samples.
Revisions:
----------
667
668
669
670
671
Modified Paths:
---------------
mail/src/main/java/javax/mail/EventQueue.java
mail/src/main/java/com/sun/mail/imap/IdleManager.java
mail/src/main/java/com/sun/mail/util/SocketFetcher.java
doc/release/CHANGES.txt
logging/src/main/java/FileErrorManager.java
logging/src/main/java/MailHandlerDemo.java
logging/src/main/java/README.txt
logging/src/main/java/SummaryFormatter.java
logging/src/main/java/maildemo.properties
publish/samples.xml
Added Paths:
------------
logging/src/main/java/maildemo.policy
Diffs:
------
diff -r 0953a8f6ec85 -r 2d69d2985dc2 mail/src/main/java/javax/mail/EventQueue.java
--- a/mail/src/main/java/javax/mail/EventQueue.java Wed Oct 01 16:03:05 2014 -0700
+++ b/mail/src/main/java/javax/mail/EventQueue.java Mon Nov 03 12:27:52 2014 -0800
@@ -66,7 +66,7 @@
* A special event that causes the queue processing task to terminate.
*/
static class TerminatorEvent extends MailEvent {
- //private static final long serialVersionUID = 5542172141759168416L;
+ private static final long serialVersionUID = -2481895000841664111L;
TerminatorEvent() {
super(new Object());
diff -r 2d69d2985dc2 -r 9e7eb9ae78b2 mail/src/main/java/com/sun/mail/imap/IdleManager.java
--- a/mail/src/main/java/com/sun/mail/imap/IdleManager.java Mon Nov 03 12:27:52 2014 -0800
+++ b/mail/src/main/java/com/sun/mail/imap/IdleManager.java Mon Nov 03 12:30:54 2014 -0800
@@ -130,7 +130,6 @@
* @since JavaMail 1.5.2
*/
public class IdleManager {
- private Executor es;
private Selector selector;
private MailLogger logger;
private volatile boolean die = false;
@@ -148,7 +147,6 @@
*/
public IdleManager(Session session, Executor es) throws IOException {
logger = new MailLogger(this.getClass(), "DEBUG IMAP", session);
- this.es = es;
selector = Selector.open();
es.execute(new Runnable() {
public void run() {
diff -r 9e7eb9ae78b2 -r 8fa698ea34b3 mail/src/main/java/com/sun/mail/util/SocketFetcher.java
--- a/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Mon Nov 03 12:30:54 2014 -0800
+++ b/mail/src/main/java/com/sun/mail/util/SocketFetcher.java Fri Nov 07 11:57:46 2014 -0800
@@ -237,8 +237,11 @@
host, port, cto, to, props, prefix, null, useSSL);
} else {
- if (to >= 0)
+ if (to >= 0) {
+ if (logger.isLoggable(Level.FINEST))
+ logger.finest("set socket read timeout " + to);
socket.setSoTimeout(to);
+ }
}
return socket;
@@ -263,6 +266,13 @@
throws IOException {
Socket socket = null;
+ if (logger.isLoggable(Level.FINEST))
+ logger.finest("create socket: prefix " + prefix +
+ ", localaddr " + localaddr + ", localport " + localport +
+ ", host " + host + ", port " + port +
+ ", connection timeout " + cto + ", timeout " + to +
+ ", socket factory " + sf + ", useSSL " + useSSL);
+
String socksHost = props.getProperty(prefix + ".socks.host", null);
int socksPort = 1080;
String err = null;
@@ -297,20 +307,29 @@
} else
socket = new Socket();
}
- if (to >= 0)
+ if (to >= 0) {
+ if (logger.isLoggable(Level.FINEST))
+ logger.finest("set socket read timeout " + to);
socket.setSoTimeout(to);
+ }
int writeTimeout = PropUtil.getIntProperty(props,
prefix + ".writetimeout", -1);
- if (writeTimeout != -1) // wrap original
+ if (writeTimeout != -1) { // wrap original
+ if (logger.isLoggable(Level.FINEST))
+ logger.finest("set socket write timeout " + writeTimeout);
socket = new WriteTimeoutSocket(socket, writeTimeout);
+ }
if (localaddr != null)
socket.bind(new InetSocketAddress(localaddr, localport));
try {
+ logger.finest("connecting...");
if (cto >= 0)
socket.connect(new InetSocketAddress(host, port), cto);
else
socket.connect(new InetSocketAddress(host, port));
+ logger.finest("success!");
} catch (IOException ex) {
+ logger.log(Level.FINEST, "connection failed", ex);
throw new SocketConnectException(err, ex, host, port, cto);
}
@@ -518,20 +537,30 @@
sslsocket.setEnabledProtocols(stringArray(protocols));
else {
/*
- * At least the UW IMAP server insists on only the TLSv1
+ * The UW IMAP server insists on at least the TLSv1
* protocol for STARTTLS, and won't accept the old SSLv2
- * or SSLv3 protocols. Here we enable only the TLSv1
- * protocol. XXX - this should probably be parameterized.
+ * or SSLv3 protocols. Here we enable only the non-SSL
+ * protocols. XXX - this should probably be parameterized.
*/
- sslsocket.setEnabledProtocols(new String[] {"TLSv1"});
+ String[] prots = sslsocket.getEnabledProtocols();
+ if (logger.isLoggable(Level.FINER))
+ logger.finer("SSL enabled protocols before " +
+ Arrays.asList(prots));
+ List<String> eprots = new ArrayList<String>();
+ for (int i = 0; i < prots.length; i++) {
+ if (prots[i] != null && !prots[i].startsWith("SSL"))
+ eprots.add(prots[i]);
+ }
+ sslsocket.setEnabledProtocols(
+ eprots.toArray(new String[eprots.size()]));
}
String ciphers = props.getProperty(prefix + ".ssl.ciphersuites", null);
if (ciphers != null)
sslsocket.setEnabledCipherSuites(stringArray(ciphers));
if (logger.isLoggable(Level.FINER)) {
- logger.finer("SSL protocols after " +
+ logger.finer("SSL enabled protocols after " +
Arrays.asList(sslsocket.getEnabledProtocols()));
- logger.finer("SSL ciphers after " +
+ logger.finer("SSL enabled ciphers after " +
Arrays.asList(sslsocket.getEnabledCipherSuites()));
}
@@ -630,7 +659,7 @@
match.invoke(hostnameChecker, new Object[] { server, cert });
return true;
} catch (InvocationTargetException cex) {
- logger.log(Level.FINER, "FAIL", cex);
+ logger.log(Level.FINER, "HostnameChecker FAIL", cex);
return false;
}
} catch (Exception ex) {
diff -r 8fa698ea34b3 -r 75b23c207789 doc/release/CHANGES.txt
--- a/doc/release/CHANGES.txt Fri Nov 07 11:57:46 2014 -0800
+++ b/doc/release/CHANGES.txt Fri Nov 07 17:04:46 2014 -0800
@@ -24,6 +24,7 @@
K 6498 IMAP idle breaks interrupt flag
K 6526 Date search terms result in wrong greater-than SEARCH commands for IMAP
K 6535 address similar to (x)<y>(z) will throw StringIndexOutOfBoundsException
+K 6551 Update logging demos to use the new 1.5.2 features
CHANGES IN THE 1.5.2 RELEASE
diff -r 8fa698ea34b3 -r 75b23c207789 logging/src/main/java/FileErrorManager.java
--- a/logging/src/main/java/FileErrorManager.java Fri Nov 07 11:57:46 2014 -0800
+++ b/logging/src/main/java/FileErrorManager.java Fri Nov 07 17:04:46 2014 -0800
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2009-2013 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2009-2013 Jason Mehrens. All Rights Reserved.
+ * Copyright (c) 2009-2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2014 Jason Mehrens. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
*/
import java.io.*;
+import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.ErrorManager;
@@ -39,9 +40,8 @@
/**
* An error manager used to store mime messages from the <tt>MailHandler</tt>
- * to the file system when the email server is unavailable or unreachable.
- * The code to manually setup this error manager can be as simple as the
- * following:
+ * to the file system when the email server is unavailable or unreachable. The
+ * code to manually setup this error manager can be as simple as the following:
* <pre>
* File dir = new File("path to dir");
* FileErrorManager em = new FileErrorManager(dir);
@@ -49,8 +49,8 @@
*
* <p>
* <b>Configuration:</b>
- * The code to setup this error manager via the logging properties
- * can be as simple as the following:
+ * The code to setup this error manager via the logging properties can be as
+ * simple as the following:
* <pre>
* #Default FileErrorManager settings.
* FileErrorManager.pattern = path to directory
@@ -82,11 +82,12 @@
private final File emailStore;
/**
- * Creates a new error manager. Files are stored in the users temp
+ * Creates a new error manager. Files are stored in the users temp
* directory.
- * @exception SecurityException if unable to access system properties or
- * if a security manager is present and unable to read or write to users
- * temp directory.
+ *
+ * @exception SecurityException if unable to access system properties or if
+ * a security manager is present and unable to read or write to users temp
+ * directory.
*/
public FileErrorManager() {
this.emailStore = getEmailStore();
@@ -95,13 +96,14 @@
/**
* Creates a new error manager.
+ *
* @param dir a directory to store the email files.
* @throws NullPointerException if <tt>dir</tt> is <tt>null</tt>
* @throws IllegalArgumentException if <tt>dir</tt> is a
* <tt>java.io.File</tt> subclass, not a directory, or is not an absolute
* path.
- * @throws SecurityException if a security manager is present and unable
- * to read or write to a given directory.
+ * @throws SecurityException if a security manager is present and unable to
+ * read or write to a given directory.
*/
public FileErrorManager(File dir) {
this.emailStore = dir;
@@ -110,25 +112,26 @@
/**
* If the message parameter is a raw email, and passes the store term, then
- * this method will store the email to the file system. If the message
+ * this method will store the email to the file system. If the message
* parameter is not a raw email then the message is forwarded to the super
* class. If an email is written to the file system without error, then the
* original reported error is ignored.
+ *
* @param msg String raw email or plain error message.
* @param ex Exception that occurred in the mail handler.
* @param code int error manager code.
*/
@Override
public void error(String msg, Exception ex, int code) {
- if (isRawEmail(msg, ex, code)) {
+ if (isRawEmail(msg)) {
try {
storeEmail(msg);
} catch (final IOException IOE) {
- super.error(emailStore.toString(), IOE, ErrorManager.WRITE_FAILURE);
next.error(msg, ex, code);
+ super.error(emailStore.toString(), IOE, ErrorManager.GENERIC_FAILURE);
} catch (final RuntimeException RE) {
- super.error(emailStore.toString(), RE, ErrorManager.WRITE_FAILURE);
next.error(msg, ex, code);
+ super.error(emailStore.toString(), RE, ErrorManager.GENERIC_FAILURE);
}
} else {
next.error(msg, ex, code);
@@ -144,7 +147,7 @@
}
File dir = this.emailStore;
- if (dir.getClass() != File.class) { //for security.
+ if (dir.getClass() != File.class) { //For security reasons.
throw new IllegalArgumentException(dir.getClass().getName());
}
@@ -152,6 +155,11 @@
throw new IllegalArgumentException("File must be a directory.");
}
+ if (!dir.canWrite()) { //Can throw under a security manager.
+ super.error(dir.getAbsolutePath(),
+ new SecurityException("write"), ErrorManager.OPEN_FAILURE);
+ }
+
//For now, only absolute paths are allowed.
if (!dir.isAbsolute()) {
throw new IllegalArgumentException("Only absolute paths are allowed.");
@@ -161,15 +169,11 @@
super.error(dir.getAbsolutePath(),
new SecurityException("read"), ErrorManager.OPEN_FAILURE);
}
-
- if (!dir.canWrite()) { //Can throw under a security manager.
- super.error(dir.getAbsolutePath(),
- new SecurityException("write"), ErrorManager.OPEN_FAILURE);
- }
}
/**
* Creates a common temp file prefix.
+ *
* @return the file prefix.
*/
private String prefixName() {
@@ -178,6 +182,7 @@
/**
* Creates a common temp file suffix.
+ *
* @return the file suffix.
*/
private String suffixName() {
@@ -186,12 +191,11 @@
/**
* Determines if the given message is a MIME message or just free text.
+ *
* @param msg the message to examine.
- * @param ex the exception that was reported.
- * @param code the ErrorManager code.
* @return true if MIME message otherwise false.
*/
- private boolean isRawEmail(String msg, Exception ex, int code) {
+ private boolean isRawEmail(String msg) {
if (msg != null && msg.length() > 0) {
return !msg.startsWith(Level.SEVERE.getName());
}
@@ -200,6 +204,7 @@
/**
* Stores the given string in a file.
+ *
* @param email the message to store.
* @throws IOException if there is a problem.
*/
@@ -219,8 +224,7 @@
}
try { //Raw email is ASCII.
- PrintStream ps = new PrintStream(
- new NewlineOutputStream(out), false, "US-ASCII");
+ PrintStream ps = new PrintStream(wrap(out), false, "US-ASCII");
ps.print(email);
ps.flush();
tmp = null; //Don't delete 'tmp' if all bytes were written.
@@ -233,6 +237,7 @@
/**
* Null safe close method.
+ *
* @param out closes the given stream.
*/
private void close(OutputStream out) {
@@ -247,6 +252,7 @@
/**
* Null safe delete method.
+ *
* @param tmp the file to delete.
*/
private void delete(File tmp) {
@@ -274,6 +280,7 @@
/**
* Gets the location of the email store.
+ *
* @return the File location.
*/
private File getEmailStore() {
@@ -283,10 +290,43 @@
dir = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
- return System.getProperty("java.io.tmpdir", "");
+ return System.getProperty("java.io.tmpdir", ".");
}
});
}
return new File(dir);
}
+
+ /**
+ * Wraps the given stream as a NewLineOutputStream.
+ *
+ * @param out the stream to wrap.
+ * @return the original or wrapped output stream.
+ */
+ private OutputStream wrap(OutputStream out) {
+ assert out != null;
+ Class<?> k;
+ try {
+ k = Class.forName("NewlineOutputStream");
+ if (OutputStream.class.isAssignableFrom(k)) {
+ Constructor<?> c = k.getConstructor(OutputStream.class);
+ return (OutputStream) c.newInstance(out);
+ } else {
+ super.error("Unable to switch newlines",
+ new ClassNotFoundException(k.getName()),
+ ErrorManager.GENERIC_FAILURE);
+ }
+ } catch (RuntimeException re) {
+ super.error("Unable to switch newlines",
+ re, ErrorManager.GENERIC_FAILURE);
+ } catch (Exception ex) {
+ super.error("Unable to switch newlines",
+ ex, ErrorManager.GENERIC_FAILURE);
+ } catch (LinkageError le) {
+ super.error("Unable to switch newlines",
+ new ClassNotFoundException("", le),
+ ErrorManager.GENERIC_FAILURE);
+ }
+ return out;
+ }
}
diff -r 8fa698ea34b3 -r 75b23c207789 logging/src/main/java/MailHandlerDemo.java
--- a/logging/src/main/java/MailHandlerDemo.java Fri Nov 07 11:57:46 2014 -0800
+++ b/logging/src/main/java/MailHandlerDemo.java Fri Nov 07 17:04:46 2014 -0800
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2009-2013 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2009-2013 Jason Mehrens. All Rights Reserved.
+ * Copyright (c) 2009-2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2014 Jason Mehrens. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,23 +30,26 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import com.sun.mail.util.logging.CollectorFormatter;
import com.sun.mail.util.logging.MailHandler;
+import com.sun.mail.util.logging.SeverityComparator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Properties;
+import java.lang.management.ManagementFactory;
+import java.util.*;
import java.util.logging.*;
+import javax.activation.DataHandler;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
/**
- * Demo for the different configurations for the MailHandler.
- * If the logging properties file or class is not specified then this
- * demo will apply some default settings to store emails in the users temp dir.
+ * Demo for the different configurations for the MailHandler. If the logging
+ * properties file or class is not specified then this demo will apply some
+ * default settings to store emails in the users temp dir.
+ *
* @author Jason Mehrens
*/
public class MailHandlerDemo {
@@ -64,34 +67,72 @@
* @param args the command line arguments
*/
public static void main(String[] args) {
- init(); //may create log messages.
- try {
- LOGGER.log(Level.FINEST, "This is the finest part of the demo.",
- new MessagingException("Fake"));
- LOGGER.log(Level.FINER, "This is the finer part of the demo.",
- new NullPointerException("Fake"));
- LOGGER.log(Level.FINE, "This is the fine part of the demo.");
- LOGGER.log(Level.CONFIG, "Logging config file is {0}.", getConfigLocation());
- LOGGER.log(Level.INFO, "Your temp directory is {0}, please wait...", getTempDir());
+ List<String> l = Arrays.asList(args);
+ if (l.contains("/?") || l.contains("-?") || l.contains("-help")) {
+ LOGGER.info("Usage: java MailHandlerDemo "
+ + "[[-all] | [-body] | [-debug] | [-low] | [-simple] "
+ + "| [-pushlevel] | [-pushfilter] | [-pushnormal]"
+ + "| [-pushonly]] "
+ + "\n\n"
+ + "-all\t\t: Execute all demos.\n"
+ + "-body\t\t: An email with all records and only a body.\n"
+ + "-debug\t\t: Output basic debug information about the JVM "
+ + "and log configuration.\n"
+ + "-low\t\t: Generates multiple emails due to low capacity."
+ + "\n"
+ + "-simple\t\t: An email with all records with body and "
+ + "an attachment.\n"
+ + "-pushlevel\t: Generates high priority emails when the"
+ + " push level is triggered and normal priority when "
+ + "flushed.\n"
+ + "-pushFilter\t: Generates high priority emails when the "
+ + "push level and the push filter is triggered and normal "
+ + "priority emails when flushed.\n"
+ + "-pushnormal\t: Generates multiple emails when the "
+ + "MemoryHandler push level is triggered. All generated "
+ + "email are sent as normal priority.\n"
+ + "-pushonly\t: Generates multiple emails when the "
+ + "MemoryHandler push level is triggered. Generates high "
+ + "priority emails when the push level is triggered and "
+ + "normal priority when flushed.\n");
+ } else {
+ init(l); //may create log messages.
+ try {
+ LOGGER.log(Level.FINEST, "This is the finest part of the demo.",
+ new MessagingException("Fake JavaMail issue."));
+ LOGGER.log(Level.FINER, "This is the finer part of the demo.",
+ new NullPointerException("Fake bug."));
+ LOGGER.log(Level.FINE, "This is the fine part of the demo.");
+ LOGGER.log(Level.CONFIG, "Logging config file is {0}.",
+ getConfigLocation());
+ LOGGER.log(Level.INFO, "Your temp directory is {0}, "
+ + "please wait...", getTempDir());
- try { //waste some time for the custom formatter.
- Thread.sleep(3L * 1000L);
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
+ try { //Waste some time for the custom formatter.
+ Thread.sleep(3L * 1000L);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+
+ LOGGER.log(Level.WARNING, "This is a warning.",
+ new FileNotFoundException("Fake file chooser issue."));
+ LOGGER.log(Level.SEVERE, "The end of the demo.",
+ new IOException("Fake access denied issue."));
+ } finally {
+ closeHandlers();
}
-
- LOGGER.log(Level.WARNING, "This is a warning.", new FileNotFoundException("Fake"));
- LOGGER.log(Level.SEVERE, "The end of the demo.", new IOException("Fake"));
- } finally {
- closeHandlers();
}
}
/**
- * Used debug problems with the logging.properties.
+ * Used debug problems with the logging.properties. The system property
+ * java.security.debug=access,stack can be used to trace access to the
+ * LogManager reset.
+ *
* @param prefix a string to prefix the output.
* @param err any PrintStream or null for System.out.
*/
+ @SuppressWarnings("UseOfSystemOutOrSystemErr")
private static void checkConfig(String prefix, PrintStream err) {
if (prefix == null || prefix.trim().length() == 0) {
prefix = "DEBUG";
@@ -102,6 +143,9 @@
}
try {
+ err.println(prefix + ": LOGGER=" + LOGGER.getLevel());
+ err.println(prefix + ": JVM id " + ManagementFactory.getRuntimeMXBean().getName());
+ err.println(prefix + ": java.security.debug=" + System.getProperty("java.security.debug"));
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
err.println(prefix + ": SecurityManager.class=" + sm.getClass().getName());
@@ -110,6 +154,17 @@
err.println(prefix + ": SecurityManager.class=" + null);
err.println(prefix + ": SecurityManager.toString=" + null);
}
+
+ String policy = System.getProperty("java.security.policy");
+ if (policy != null) {
+ File f = new File(policy);
+ err.println(prefix + ": AbsolutePath=" + f.getAbsolutePath());
+ err.println(prefix + ": CanonicalPath=" + f.getCanonicalPath());
+ err.println(prefix + ": length=" + f.length());
+ err.println(prefix + ": canRead=" + f.canRead());
+ err.println(prefix + ": lastModified="
+ + new java.util.Date(f.lastModified()));
+ }
LogManager manager = LogManager.getLogManager();
String key = "java.util.logging.config.file";
@@ -123,22 +178,26 @@
err.println(prefix + ": canRead=" + f.canRead());
err.println(prefix + ": lastModified="
+ new java.util.Date(f.lastModified()));
- //force any errors, only safe is key is present.
+ //Force any errors. This is only safe if key is present.
manager.readConfiguration();
} else {
err.println(prefix + ": " + key + " is not set as a system property.");
}
err.println(prefix + ": LogManager.class=" + manager.getClass().getName());
err.println(prefix + ": LogManager.toString=" + manager);
+ err.println(prefix + ": MailHandler classLoader=" + MailHandler.class.getClassLoader());
+ err.println(prefix + ": Context ClassLoader=" + Thread.currentThread().getContextClassLoader());
+ err.println(prefix + ": Session ClassLoader=" + Session.class.getClassLoader());
+ err.println(prefix + ": DataHandler ClassLoader=" + DataHandler.class.getClassLoader());
final String p = MailHandler.class.getName();
key = p.concat(".mail.to");
String to = manager.getProperty(key);
err.println(prefix + ": TO=" + to);
- err.println(prefix + ": TO="
- + Arrays.toString(InternetAddress.parse(to, false)));
- err.println(prefix + ": TO="
- + Arrays.toString(InternetAddress.parse(to, true)));
+ if (to != null) {
+ err.println(prefix + ": TO="
+ + Arrays.toString(InternetAddress.parse(to, true)));
+ }
key = p.concat(".mail.from");
String from = manager.getProperty(key);
@@ -152,15 +211,99 @@
err.println(prefix + ": FROM="
+ Arrays.asList(InternetAddress.parse(from, true)));
}
+
+ synchronized (manager) {
+ final Enumeration<String> e = manager.getLoggerNames();
+ while (e.hasMoreElements()) {
+ final Logger l = manager.getLogger(e.nextElement());
+ if (l != null) {
+ final Handler[] handlers = l.getHandlers();
+ if (handlers.length > 0) {
+ err.println(prefix + ": " + l.getClass().getName()
+ + ", " + l.getName());
+ for (Handler h : handlers) {
+ err.println(prefix + ":\t" + toString(prefix, err, h));
+ }
+ }
+ }
+ }
+ }
} catch (Throwable error) {
err.print(prefix + ": ");
error.printStackTrace(err);
}
+ err.flush();
}
/**
- * Example for body only messages.
- * On close the remaining messages are sent.
+ * Gets a formatting string describing the given handler.
+ *
+ * @param prefix the output prefix.
+ * @param err the error stream.
+ * @param h the handler.
+ * @return the formatted string.
+ */
+ private static String toString(String prefix, PrintStream err, Handler h) {
+ StringBuilder buf = new StringBuilder();
+ buf.append(h.getClass().getName());
+ try {
+ if (h instanceof MailHandler) {
+ MailHandler mh = (MailHandler) h;
+ buf.append(", ").append(mh.getSubject());
+ }
+ } catch (SecurityException error) {
+ err.print(prefix + ": ");
+ error.printStackTrace(err);
+ }
+
+ try {
+ buf.append(", ").append(h.getFormatter());
+ } catch (SecurityException error) {
+ err.print(prefix + ": ");
+ error.printStackTrace(err);
+ }
+
+ try {
+ if (h instanceof MailHandler) {
+ MailHandler mh = (MailHandler) h;
+ buf.append(", ").append(Arrays.toString(
+ mh.getAttachmentFormatters()));
+ }
+ } catch (SecurityException error) {
+ err.print(prefix + ": ");
+ error.printStackTrace(err);
+ }
+
+ try {
+ buf.append(", ").append(h.getLevel());
+ } catch (SecurityException error) {
+ err.print(prefix + ": ");
+ error.printStackTrace(err);
+ }
+
+ try {
+ buf.append(", ").append(h.getFilter());
+ } catch (SecurityException error) {
+ err.print(prefix + ": ");
+ error.printStackTrace(err);
+ }
+
+ try {
+ buf.append(", ").append(h.getErrorManager());
+ } catch (SecurityException error) {
+ err.print(prefix + ": ");
+ error.printStackTrace(err);
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Example for body only messages. On close the remaining messages are sent. <code>
+ * ##logging.properties
+ * MailHandlerDemo.handlers=com.sun.mail.util.logging.MailHandler
+ * com.sun.mail.util.logging.MailHandler.subject=Body only demo
+ * ##
+ * </code>
*/
private static void initBodyOnly() {
MailHandler h = new MailHandler();
@@ -169,10 +312,16 @@
}
/**
- * Example showing that when the mail handler reaches capacity it
- * will format and send the current records. Capacity is used to roughly
- * limit the size of an outgoing message.
- * On close any remaining messages are sent.
+ * Example showing that when the mail handler reaches capacity it will
+ * format and send the current records. Capacity is used to roughly limit
+ * the size of an outgoing message. On close any remaining messages are
+ * sent. <code>
+ * ##logging.properties
+ * MailHandlerDemo.handlers=com.sun.mail.util.logging.MailHandler
+ * com.sun.mail.util.logging.MailHandler.subject=Low capacity demo
+ * com.sun.mail.util.logging.MailHandler.capacity=5
+ * ##
+ * </code>
*/
private static void initLowCapacity() {
MailHandler h = new MailHandler(5);
@@ -181,21 +330,33 @@
}
/**
- * Example for body only messages.
- * On close any remaining messages are sent.
+ * Example for body only messages. On close any remaining messages are sent. <code>
+ * ##logging.properties
+ * MailHandlerDemo.handlers=com.sun.mail.util.logging.MailHandler
+ * com.sun.mail.util.logging.MailHandler.subject=Body and attachment demo
+ * com.sun.mail.util.logging.MailHandler.attachment.formatters=java.util.logging.XMLFormatter
+ * com.sun.mail.util.logging.MailHandler.attachment.names=data.xml
+ * ##
+ * </code>
*/
private static void initSimpleAttachment() {
MailHandler h = new MailHandler();
h.setSubject("Body and attachment demo");
- h.setAttachmentFormatters(new Formatter[]{new XMLFormatter()});
- h.setAttachmentNames(new String[]{"data.xml"});
+ h.setAttachmentFormatters(new XMLFormatter());
+ h.setAttachmentNames("data.xml");
LOGGER.addHandler(h);
}
/**
- * Example setup for priority messages by level.
- * If the push level is triggered the message is high priority.
- * Otherwise, on close any remaining messages are sent.
+ * Example setup for priority messages by level. If the push level is
+ * triggered the message is high priority. Otherwise, on close any remaining
+ * messages are sent. <code>
+ * ##logging.properties
+ * MailHandlerDemo.handlers=com.sun.mail.util.logging.MailHandler
+ * com.sun.mail.util.logging.MailHandler.subject=Push level demo
+ * com.sun.mail.util.logging.MailHandler.pushLevel=WARNING
+ * ##
+ * </code>
*/
private static void initWithPushLevel() {
MailHandler h = new MailHandler();
@@ -205,9 +366,16 @@
}
/**
- * Example for priority messages by custom trigger.
- * If the push filter is triggered the message is high priority.
- * Otherwise, on close any remaining messages are sent.
+ * Example for priority messages by custom trigger. If the push filter is
+ * triggered the message is high priority. Otherwise, on close any remaining
+ * messages are sent. <code>
+ * ##logging.properties
+ * MailHandlerDemo.handlers=com.sun.mail.util.logging.MailHandler
+ * com.sun.mail.util.logging.MailHandler.subject=Push on MessagingException demo
+ * com.sun.mail.util.logging.MailHandler.pushLevel=ALL
+ * com.sun.mail.util.logging.MailHandler.pushFilter=MailHandlerDemo$MessageErrorsFilter
+ * ##
+ * </code>
*/
private static void initWithPushFilter() {
MailHandler h = new MailHandler();
@@ -218,11 +386,21 @@
}
/**
- * Example for circular buffer behavior. The level, push level, and
- * capacity are set the same so that the memory handler push results
- * in a mail handler push. All messages are high priority.
- * On close any remaining records are discarded because they never reach
- * the mail handler.
+ * Example for circular buffer behavior. The level, push level, and capacity
+ * are set the same so that the memory handler push results in a mail
+ * handler push. All messages are high priority. On close any remaining
+ * records are discarded because they never reach the mail handler. <code>
+ * ##logging.properties
+ * MailHandlerDemo.handlers=java.util.logging.MemoryHandler
+ * java.util.logging.MemoryHandler.target=com.sun.mail.util.logging.MailHandler
+ * com.sun.mail.util.logging.MailHandler.level=ALL
+ * java.util.logging.MemoryHandler.level=ALL
+ * java.util.logging.MemoryHandler.push=WARNING
+ * com.sun.mail.util.logging.MailHandler.subject=Push on MessagingException demo
+ * com.sun.mail.util.logging.MailHandler.pushLevel=ALL
+ * com.sun.mail.util.logging.MailHandler.pushFilter=MailHandlerDemo$MessageErrorsFilter
+ * ##
+ * </code>
*/
private static void initPushOnly() {
final int capacity = 3;
@@ -237,17 +415,18 @@
}
/**
- * Holds on to the push only handler.
- * Only declared here to apply fallback settings.
+ * Holds on to the push only handler. Only declared here to apply fallback
+ * settings.
*/
private static Handler pushOnlyHandler;
/**
- * Example for circular buffer behavior as normal priority. The push level,
- * and capacity are set the same so that the memory handler push results
- * in a mail handler push. All messages are normal priority.
- * On close any remaining records are discarded because they never reach
- * the mail handler.
+ * Example for circular buffer behavior as normal priority. The push level,
+ * and capacity are set the same so that the memory handler push results in
+ * a mail handler push. All messages are normal priority. On close any
+ * remaining records are discarded because they never reach the mail
+ * handler. Use the LogManager config option or extend the MemoryHandler to
+ * emulate this behavior via the logging.properties.
*/
private static void initPushNormal() {
final int capacity = 3;
@@ -266,68 +445,106 @@
}
/**
- * Holds on to the push normal handler.
- * Only declared here to apply fallback settings.
+ * Holds on to the push normal handler. Only declared here to apply fallback
+ * settings.
*/
private static Handler pushNormalHandler;
/**
- * Example for various kinds of custom sorting, formatting, and filtering
- * for multiple attachment messages.
- * On close any remaining messages are sent.
+ * Example for various kinds of custom sorting, formatting, and filtering
+ * for multiple attachment messages. The subject will contain the most
+ * severe record and a count of remaining records. The log records are
+ * ordered from most severe to least severe. The body uses a custom
+ * formatter that includes a summary by date and time. The attachment use
+ * XML and plain text formats. Each attachment has a different set of
+ * filtering. The attachment names are generated from either a fixed name or
+ * are built using the number and type of the records formatted. On close
+ * any remaining messages are sent. Use the LogManager config option or
+ * extend the MemoryHandler to emulate this behavior via the
+ * logging.properties.
*/
private static void initCustomAttachments() {
MailHandler h = new MailHandler();
//Sort records by level keeping the severe messages at the top.
- h.setComparator(new LevelAndSeqComparator(true));
+ h.setComparator(Collections.reverseOrder(new SeverityComparator()));
//Use subject to provide a hint as to what is in the email.
- h.setSubject(new SummaryNameFormatter("Log containing {0} records with {1} errors"));
+ h.setSubject(new CollectorFormatter());
//Make the body give a simple summary of what happened.
h.setFormatter(new SummaryFormatter());
//Create 3 attachments.
- h.setAttachmentFormatters(new Formatter[]{new XMLFormatter(), new XMLFormatter(), new SimpleFormatter()});
+ h.setAttachmentFormatters(new XMLFormatter(),
+ new XMLFormatter(), new SimpleFormatter());
- //filter each attachment differently.
- h.setAttachmentFilters(new Filter[]{null, new MessageErrorsFilter(false),
- new MessageErrorsFilter(true)});
+ //Filter each attachment differently.
+ h.setAttachmentFilters(null, new MessageErrorsFilter(false),
+ new MessageErrorsFilter(true));
-
- //create simple names.
- h.setAttachmentNames(new String[]{"all.xml", "errors.xml", "errors.txt"});
-
- //extract simple name, replace the rest with formatters.
- h.setAttachmentNames(new Formatter[]{h.getAttachmentNames()[0],
- new SummaryNameFormatter("{0} records and {1} errors"),
- new SummaryNameFormatter("{0,choice,0#no records|1#1 record|"
- + "1<{0,number,integer} records} and "
- + "{1,choice,0#no errors|1#1 error|1<"
- + "{1,number,integer} errors}")});
+ //Creating the attachment name formatters.
+ h.setAttachmentNames(new CollectorFormatter("all.xml"),
+ new CollectorFormatter("{3} records and {5} errors.xml"),
+ new CollectorFormatter("{5,choice,0#no errors|1#1 error|1<"
+ + "{5,number,integer} errors}.txt"));
LOGGER.addHandler(h);
}
/**
* Sets up the demos that will run.
+ *
+ * @param l the list of arguments.
*/
- private static void init() {
+ private static void init(List<String> l) {
+ l = new ArrayList<String>(l);
Session session = Session.getInstance(System.getProperties());
- if (session.getDebug()) {
+ boolean all = l.remove("-all") || l.isEmpty();
+ if (l.remove("-body") || all) {
+ initBodyOnly();
+ }
+
+ if (l.remove("-custom") || all) {
+ initCustomAttachments();
+ }
+
+ if (l.remove("-low") || all) {
+ initLowCapacity();
+ }
+
+ if (l.remove("-pushfilter") || all) {
+ initWithPushFilter();
+ }
+
+ if (l.remove("-pushlevel") || all) {
+ initWithPushLevel();
+ }
+
+ if (l.remove("-pushnormal") || all) {
+ initPushNormal();
+ }
+
+ if (l.remove("-pushonly") || all) {
+ initPushOnly();
+ }
+
+ if (l.remove("-simple") || all) {
+ initSimpleAttachment();
+ }
+
+ boolean fallback = applyFallbackSettings();
+ if (l.remove("-debug") || session.getDebug()) {
checkConfig(CLASS_NAME, session.getDebugOut());
}
- initBodyOnly();
- initLowCapacity();
- initSimpleAttachment();
- initWithPushLevel();
- initWithPushFilter();
- initCustomAttachments();
- initPushOnly();
- initPushNormal();
- applyFallbackSettings();
+ if (!l.isEmpty()) {
+ LOGGER.log(Level.SEVERE, "Unknown commands: {0}", l);
+ }
+
+ if (fallback) {
+ LOGGER.info("Check your user temp dir for output.");
+ }
}
/**
@@ -335,8 +552,7 @@
*/
private static void closeHandlers() {
Handler[] handlers = LOGGER.getHandlers();
- for (int i = 0; i < handlers.length; i++) {
- Handler h = handlers[i];
+ for (Handler h : handlers) {
h.close();
LOGGER.removeHandler(h);
}
@@ -344,23 +560,26 @@
/**
* Apply some fallback settings if no configuration file was specified.
+ *
+ * @return true if fallback settings were applied.
*/
- private static void applyFallbackSettings() {
+ private static boolean applyFallbackSettings() {
if (getConfigLocation() == null) {
LOGGER.setLevel(Level.ALL);
- LOGGER.info("Check your user temp dir for output.");
Handler[] handlers = LOGGER.getHandlers();
- for (int i = 0; i < handlers.length; i++) {
- Handler h = handlers[i];
+ for (Handler h : handlers) {
fallbackSettings(h);
}
fallbackSettings(pushOnlyHandler);
fallbackSettings(pushNormalHandler);
+ return true;
}
+ return false;
}
/**
* Common fallback settings for a single handler.
+ *
* @param h the handler.
*/
private static void fallbackSettings(Handler h) {
@@ -372,6 +591,7 @@
/**
* Gets the system temp directory.
+ *
* @return the system temp directory.
*/
private static String getTempDir() {
@@ -380,6 +600,7 @@
/**
* Gets the configuration file or class name.
+ *
* @return the file name or class name.
*/
private static String getConfigLocation() {
@@ -393,7 +614,7 @@
/**
* A simple message filter example.
*/
- private static final class MessageErrorsFilter implements Filter {
+ public static final class MessageErrorsFilter implements Filter {
/**
* Used to negate this filter.
@@ -403,15 +624,16 @@
/**
* Default constructor.
*/
- MessageErrorsFilter() {
+ public MessageErrorsFilter() {
this(true);
}
/**
* Creates the message filter.
+ *
* @param complement used to allow or deny message exceptions.
*/
- MessageErrorsFilter(final boolean complement) {
+ public MessageErrorsFilter(final boolean complement) {
this.complement = complement;
}
@@ -419,72 +641,4 @@
return r.getThrown() instanceof MessagingException == complement;
}
}
-
- /**
- * Orders log records by level then sequence number.
- */
- private static final class LevelAndSeqComparator
- implements Comparator<LogRecord>, java.io.Serializable {
-
- /**
- * Generated serial id.
- */
- private static final long serialVersionUID = 6269562326337300267L;
-
- /**
- * Used to reverse the ordering.
- */
- private final boolean reverse;
-
- /**
- * The default constructor.
- */
- LevelAndSeqComparator() {
- this(false);
- }
-
- /**
- * Creates the comparator.
- * @param reverse to specify reverse ordering.
- */
- LevelAndSeqComparator(final boolean reverse) {
- this.reverse = reverse;
- }
-
- /**
- * Compare by level.
- * @param r1 the first log record.
- * @param r2 the second log record.
- * @return -1 for less than, 0 for equal, or 1 for greater than.
- */
- public int compare(LogRecord r1, LogRecord r2) {
- final int first = r1.getLevel().intValue();
- final int second = r2.getLevel().intValue();
- if (first < second) {
- return reverse ? 1 : -1;
- } else if (first > second) {
- return reverse ? -1 : 1;
- } else {
- return compareSeq(r1, r2);
- }
- }
-
- /**
- * Compare by sequence.
- * @param r1 the first log record.
- * @param r2 the second log record.
- * @return -1 for less than, 0 for equal, or 1 for greater than.
- */
- private int compareSeq(LogRecord r1, LogRecord r2) {
- final long first = r1.getSequenceNumber();
- final long second = r2.getSequenceNumber();
- if (first < second) {
- return reverse ? 1 : -1;
- } else if (first > second) {
- return reverse ? -1 : 1;
- } else {
- return 0;
- }
- }
- }
}
diff -r 8fa698ea34b3 -r 75b23c207789 logging/src/main/java/README.txt
--- a/logging/src/main/java/README.txt Fri Nov 07 11:57:46 2014 -0800
+++ b/logging/src/main/java/README.txt Fri Nov 07 17:04:46 2014 -0800
@@ -12,7 +12,7 @@
1. The demo requires Java version 1.5 or newer.
We *strongly* encourage you to use the latest version of J2SE,
- which you can download from
+ which you can download from
http://www.oracle.com/technetwork/java/javase/downloads.
2. Set your CLASSPATH to include the "mail.jar" and "activation.jar".
@@ -30,8 +30,8 @@
4. Compile all the files using your Java compiler. For example:
javac *.java
-
- 5. Not required but, you should edit the maildemo.properties and change the
+
+ 5. Not required but, you should edit the maildemo.properties and change the
mail.to address and mail.host to your mail server ip or host name.
6. Run the demo. For example:
@@ -50,22 +50,53 @@
initXXX methods describe some of the
common setup code for different types
of email messages.
-
+
+ Usage: java MailHandlerDemo [[-all] | [-body] | [-debug]
+ | [-low] | [-simple] | [-pushlevel]
+ | [-pushfilter] | [-pushnormal]| [-pushonly]]
+
+ Options:
+ -all : Execute all demos.
+ -body : An email with all records and only a body.
+ -debug : Output basic debug information about the
+ JVM and log configuration.
+ -low : Generates multiple emails due to low
+ capacity.
+ -simple : An email with all records with body and an
+ attachment.
+ -pushlevel : Generates high priority emails when
+ the push level is triggered and
+ normal priority when flushed.
+ -pushFilter : Generates high priority emails when
+ the push level and the push filter
+ is triggered and normal priority
+ emails when flushed.
+ -pushnormal : Generates multiple emails when the
+ MemoryHandler push level is
+ triggered. All generated email are
+ sent as normal priority.
+ -pushonly : Generates multiple emails when the
+ MemoryHandler push level is
+ triggered. Generates high priority
+ emails when the push level is
+ triggered and normal priority when
+ flushed.
+
+
FileErrorManager = Used to store email messages to the
local file system when mail transport
fails. This is installed as a
fallback in case the logging config is
not specified.
- SummaryFormatter = An example compact formatter for the
- body of an email message.
-
- SummaryNameFormatter = An example formatter used to generate
- subject lines and attachment file
- names based on the contents of the
- email message.
+ SummaryFormatter = An example compact formatter with summary
+ for use with the body of an email message.
Support files:
maildemo.properties = A sample LogManager properties file for
the MailHandlerDemo.
+
+ maildemo.policy = A sample security policy file to use with
+ the MailHandlerDemo. This can be used to
+ enable security tracing.
diff -r 8fa698ea34b3 -r 75b23c207789 logging/src/main/java/SummaryFormatter.java
--- a/logging/src/main/java/SummaryFormatter.java Fri Nov 07 11:57:46 2014 -0800
+++ b/logging/src/main/java/SummaryFormatter.java Fri Nov 07 17:04:46 2014 -0800
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2009-2013 Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2009-2013 Jason Mehrens. All Rights Reserved.
+ * Copyright (c) 2009-2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009-2014 Jason Mehrens. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,8 +30,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-import java.text.DateFormat;
-import java.util.Date;
+import com.sun.mail.util.logging.CollectorFormatter;
+import com.sun.mail.util.logging.CompactFormatter;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
@@ -41,93 +41,61 @@
*
* @author Jason Mehrens
*/
-public class SummaryFormatter extends Formatter {
+public final class SummaryFormatter extends Formatter {
/**
- * The oldest record.getMillis() recorded.
+ * The line formatter.
*/
- private long oldest;
+ private final CompactFormatter format;
/**
- * The newest record.getMillis() recorded.
+ * The footer formatter.
*/
- private long newest;
- /**
- * The number of log records formatted before the tail is written.
- */
- private long count;
+ private final CollectorFormatter footer;
/**
* Creates the formatter.
*/
public SummaryFormatter() {
- reset();
+ format = new CompactFormatter("[%4$s]\t%5$s %6$s%n");
+ footer = new CollectorFormatter("\nThese {3} messages occurred between "
+ + "{7,time,EEE, MMM dd HH:mm:ss:S ZZZ yyyy} and "
+ + "{8,time,EEE, MMM dd HH:mm:ss:S ZZZ yyyy}\n", format, null);
}
+ /**
+ * Gets the header information.
+ *
[truncated due to length]