/* * Copyright (c) 2009-2012 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2009-2012 Jason Mehrens. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import com.sun.mail.util.logging.MailHandler; import java.util.logging.*; import javax.mail.*; import javax.mail.internet.InternetAddress; import java.util.Arrays; import java.util.Comparator; import java.util.Properties; import java.io.*; /** * 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 { private static final String CLASS_NAME = MailHandlerDemo.class.getName(); private static final Logger LOGGER = Logger.getLogger(CLASS_NAME); /** * @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()); 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")); LOGGER.log(Level.SEVERE, "The end of the demo.", new IOException("Fake")); } finally { closeHandlers(); } } /** * Used debug problems with the logging.properties. * @param prefix a string to prefix the output. * @param err any PrintStream or null for System.out. */ private static void checkConfig(String prefix, PrintStream err) { if (prefix == null || prefix.trim().length() == 0) { prefix = "DEBUG"; } if (err == null) { err = System.out; } try { SecurityManager sm = System.getSecurityManager(); if (sm != null) { err.println(prefix + ": SecurityManager.class=" + sm.getClass().getName()); err.println(prefix + ": SecurityManager.toString=" + sm); } else { err.println(prefix + ": SecurityManager.class=" + null); err.println(prefix + ": SecurityManager.toString=" + null); } LogManager manager = LogManager.getLogManager(); String key = "java.util.logging.config.file"; String cfg = System.getProperty(key); if (cfg != null) { err.println(prefix + ": " + cfg); File f = new File(cfg); 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())); //force any errors, only safe is 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); 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.asList(InternetAddress.parse(to, false))); err.println(prefix + ": TO=" + Arrays.asList(InternetAddress.parse(to, true))); key = p.concat(".mail.from"); String from = manager.getProperty(key); if (from == null || from.length() == 0) { Session session = Session.getInstance(new Properties()); InternetAddress local = InternetAddress.getLocalAddress(session); err.println(prefix + ": FROM=" + local); } else { err.println(prefix + ": FROM=" + Arrays.asList(InternetAddress.parse(from, false))); err.println(prefix + ": FROM=" + Arrays.asList(InternetAddress.parse(from, true))); } } catch (Throwable error) { err.print(prefix + ": "); error.printStackTrace(err); } } /** * Example for body only messages. * On close the remaining messages are sent. */ private static void initBodyOnly() { MailHandler h = new MailHandler(); h.setSubject("Body only demo"); LOGGER.addHandler(h); } /** * 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. */ private static void initLowCapacity() { MailHandler h = new MailHandler(5); h.setSubject("Low capacity demo"); LOGGER.addHandler(h); } /** * Example for body only messages. * On close any remaining messages are sent. */ 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"}); 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. */ private static void initWithPushLevel() { MailHandler h = new MailHandler(); h.setSubject("Push level demo"); h.setPushLevel(Level.WARNING); LOGGER.addHandler(h); } /** * 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. */ private static void initWithPushFilter() { MailHandler h = new MailHandler(); h.setSubject("Push on MessagingException demo"); h.setPushLevel(Level.ALL); h.setPushFilter(new MessageErrorsFilter(true)); LOGGER.addHandler(h); } /** * 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. */ private static void initPushOnly() { final int capacity = 3; final Level pushLevel = Level.WARNING; final MailHandler h = new MailHandler(capacity); h.setPushLevel(pushLevel); h.setSubject("Push only demo"); MemoryHandler m = new MemoryHandler(h, capacity, pushLevel); h.setLevel(m.getLevel()); LOGGER.addHandler(m); pushOnlyHandler = h; } 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. */ private static void initPushNormal() { final int capacity = 3; final MailHandler h = new MailHandler(capacity); h.setSubject("Push normal demo"); MemoryHandler m = new MemoryHandler(h, capacity, Level.WARNING) { public void push() { super.push(); //push to target. super.flush(); //make the target send the email. } }; LOGGER.addHandler(m); pushNormalHandler = h; } 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. */ private static void initCustomAttachments() { MailHandler h = new MailHandler(); //Sort records by level keeping the severe messages at the top. h.setComparator(new LevelAndSeqComparator(true)); //Use subject to provide a hint as to what is in the email. h.setSubject(new SummaryNameFormatter("Log containing {0} records with {1} errors")); //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()}); //filter each attachment differently. h.setAttachmentFilters(new Filter[]{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}")}); LOGGER.addHandler(h); } /** * Sets up the demos that will run. */ private static void init() { Session session = Session.getInstance(System.getProperties()); if (session.getDebug()) { checkConfig(CLASS_NAME, session.getDebugOut()); } initBodyOnly(); initLowCapacity(); initSimpleAttachment(); initWithPushLevel(); initWithPushFilter(); initCustomAttachments(); initPushOnly(); initPushNormal(); applyFallbackSettings(); } private static void closeHandlers() { Handler[] handlers = LOGGER.getHandlers(); for (int i = 0; i < handlers.length; i++) { Handler h = handlers[i]; h.close(); LOGGER.removeHandler(h); } } private static void 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]; fallbackSettings(h); } fallbackSettings(pushOnlyHandler); fallbackSettings(pushNormalHandler); } } private static void fallbackSettings(Handler h) { if (h != null) { h.setErrorManager(new FileErrorManager()); h.setLevel(Level.ALL); } } private static String getTempDir() { return System.getProperty("java.io.tmpdir"); } private static String getConfigLocation() { String file = System.getProperty("java.util.logging.config.file"); if (file == null) { return System.getProperty("java.util.logging.config.class"); } return file; } private static final class MessageErrorsFilter implements Filter { private final boolean complement; MessageErrorsFilter(final boolean complement) { this.complement = complement; } public boolean isLoggable(LogRecord r) { return r.getThrown() instanceof MessagingException == complement; } } /** * Orders log records by level then sequence number. */ private static final class LevelAndSeqComparator implements Comparator, java.io.Serializable { private static final long serialVersionUID = 6269562326337300267L; private final boolean reverse; LevelAndSeqComparator() { this(false); } LevelAndSeqComparator(final boolean reverse) { this.reverse = reverse; } public int compare(Object o1, Object o2) { LogRecord r1 = (LogRecord) o1; LogRecord r2 = (LogRecord) o2; 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); } } 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; } } } }