From 624e2c4d5f616c6edb1c2105b7a87f471cd1f668 Mon Sep 17 00:00:00 2001 From: jmehrens Date: Mon, 29 Jan 2024 16:52:25 -0600 Subject: [PATCH] MailHander should catch ServiceConfigurationError #123 Signed-off-by: jmehrens --- doc/src/main/resources/docs/CHANGES.txt | 1 + .../angus/mail/util/logging/MailHandler.java | 519 +++++++++++------- .../mail/util/logging/MailHandlerTest.java | 340 +++++++----- 3 files changed, 546 insertions(+), 314 deletions(-) diff --git a/doc/src/main/resources/docs/CHANGES.txt b/doc/src/main/resources/docs/CHANGES.txt index 23a784e..3b76bea 100644 --- a/doc/src/main/resources/docs/CHANGES.txt +++ b/doc/src/main/resources/docs/CHANGES.txt @@ -16,6 +16,7 @@ The following bugs have been fixed in the 2.0.3 release. 107: java.io.UnsupportedEncodingException: en_US.iso885915 if charset is "en_US.iso885915" 110: WildFly support for MailHandler 116: MailHandler LogManger support for mail entries +123: MailHander should catch ServiceConfigurationError CHANGES IN THE 2.0.2 RELEASE ---------------------------- diff --git a/mailhandler/src/main/java/org/eclipse/angus/mail/util/logging/MailHandler.java b/mailhandler/src/main/java/org/eclipse/angus/mail/util/logging/MailHandler.java index aeced38..f50ffa1 100644 --- a/mailhandler/src/main/java/org/eclipse/angus/mail/util/logging/MailHandler.java +++ b/mailhandler/src/main/java/org/eclipse/angus/mail/util/logging/MailHandler.java @@ -68,6 +68,7 @@ import java.util.Objects; import java.util.Properties; import java.util.ResourceBundle; +import java.util.ServiceConfigurationError; import java.util.logging.ErrorManager; import java.util.logging.Filter; import java.util.logging.Formatter; @@ -408,6 +409,10 @@ public class MailHandler extends Handler { * Min byte size for header data. Used for initial arrays sizing. */ private static final int MIN_HEADER_SIZE = 1024; + /** + * Default capacity for the log record storage. + */ + private static final int DEFAULT_CAPACITY = 1000; /** * Cache the off value. */ @@ -444,11 +449,16 @@ public class MailHandler extends Handler { * This must be less than the PUBLISH state. */ private static final Integer MUTEX_REPORT = -4; + /** + * The used for service configuration error reporting. + * This must be less than the REPORT state and less than linkage. + */ + private static final Integer MUTEX_SERVICE = -8; /** * The used for linkage error reporting. * This must be less than the REPORT state. */ - private static final Integer MUTEX_LINKAGE = -8; + private static final Integer MUTEX_LINKAGE = -16; /** * Used to turn off security checks. */ @@ -461,7 +471,7 @@ public class MailHandler extends Handler { /** * Holds all of the email server properties. */ - private Properties mailProps; + private Properties mailProps = new Properties(); /** * Holds the authenticator required to login to the email server. */ @@ -491,6 +501,7 @@ public class MailHandler extends Handler { * The maximum number of log records to format per email. * Used to roughly bound the size of an email. * Every time the capacity is reached, the handler will push. + * Capacity is zero while the handler is being constructed. * The capacity will be negative if this handler is closed. * Negative values are used to ensure all records are pushed. */ @@ -517,7 +528,7 @@ public class MailHandler extends Handler { * This is only required if an email must be sent prior to shutdown * or before the buffer is full. */ - private Level pushLevel; + private Level pushLevel = Level.OFF; /** * Holds the push filter for trigger conditions requiring an early push. * Only gets called if the given log record is greater than or equal @@ -530,10 +541,11 @@ public class MailHandler extends Handler { */ private volatile Filter filter; /** - * Holds the level for this handler. + * Holds the level for this handler. Default value must be OFF. * There is no way to un-seal the super handler. + * @see #init(java.util.Properties) */ - private volatile Level logLevel = Level.ALL; + private volatile Level logLevel = Level.OFF; /** * Holds the filters for each attachment. Filters are optional for * each attachment. This is declared volatile because this is treated as @@ -541,14 +553,14 @@ public class MailHandler extends Handler { * positive. */ @SuppressWarnings("VolatileArrayField") - private volatile Filter[] attachmentFilters; + private volatile Filter[] attachmentFilters = emptyFilterArray(); /** * Holds the encoding name for this handler. * There is no way to un-seal the super handler. */ private String encoding; /** - * Holds the entry and body filter for this handler. + * Holds the body formatter for this handler. * There is no way to un-seal the super handler. */ private Formatter formatter; @@ -558,14 +570,14 @@ public class MailHandler extends Handler { * getHead, format, and getTail methods are only called if one or more * log records pass through the attachment filters. */ - private Formatter[] attachmentFormatters; + private Formatter[] attachmentFormatters = emptyFormatterArray(); /** * Holds the formatters that create the file name for each attachment. * Each formatter must produce a non null and non empty name. * The final file name will be the concatenation of one getHead call, plus * all of the format calls, plus one getTail call. */ - private Formatter[] attachmentNames; + private Formatter[] attachmentNames = emptyFormatterArray(); /** * Used to override the content type for the body and set the content type * for each attachment. @@ -575,6 +587,7 @@ public class MailHandler extends Handler { * Holds the error manager for this handler. * There is no way to un-seal the super handler. */ + @SuppressWarnings("this-escape") private volatile ErrorManager errorManager = defaultErrorManager(); /** @@ -584,6 +597,7 @@ public class MailHandler extends Handler { * @throws SecurityException if a security manager exists and the * caller does not have LoggingPermission("control"). */ + @SuppressWarnings("this-escape") public MailHandler() { init((Properties) null); } @@ -593,10 +607,12 @@ public MailHandler() { * LogManager configuration properties but overrides the * LogManager capacity with the given capacity. * - * @param capacity of the internal buffer. + * @param capacity of the internal buffer. If less than one the default of + * 1000 is used. * @throws SecurityException if a security manager exists and the * caller does not have LoggingPermission("control"). */ + @SuppressWarnings("this-escape") public MailHandler(final int capacity) { init((Properties) null); setCapacity0(capacity); @@ -613,6 +629,7 @@ public MailHandler(final int capacity) { * @throws SecurityException if a security manager exists and the * caller does not have LoggingPermission("control"). */ + @SuppressWarnings("this-escape") public MailHandler(Properties props) { init(props); //Must pass null or original object } @@ -685,6 +702,8 @@ public void publish(final LogRecord record) { } } catch (final LinkageError JDK8152515) { reportLinkageError(JDK8152515, ErrorManager.WRITE_FAILURE); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, ErrorManager.WRITE_FAILURE); } finally { releaseMutex(); } @@ -911,8 +930,8 @@ public void flush() { */ @Override public void close() { + checkAccess(); try { - checkAccess(); //Ensure setLevel works before clearing the buffer. Message msg = null; synchronized (this) { try { @@ -920,6 +939,7 @@ public void close() { } finally { //Change level after formatting. this.logLevel = Level.OFF; this.disabledLevel = null; //free reference + /** * The sign bit of the capacity is set to ensure that * records that have passed isLoggable, but have yet to be @@ -930,10 +950,10 @@ public void close() { this.capacity = -this.capacity; } + //Only need room for one record after closed //Ensure not inside a push. if (size == 0 && data.length != 1) { - this.data = new LogRecord[1]; - this.matched = new int[this.data.length]; + initLogRecords(1); } } } @@ -943,6 +963,8 @@ public void close() { } } catch (final LinkageError JDK8152515) { reportLinkageError(JDK8152515, ErrorManager.CLOSE_FAILURE); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, ErrorManager.CLOSE_FAILURE); } } @@ -954,8 +976,10 @@ public void close() { * @see #setLevel(java.util.logging.Level) * @since Angus Mail 2.0.3 */ - public boolean isEnabled() { - return this.logLevel.intValue() != offValue; //Volatile read + public synchronized boolean isEnabled() { + //For a this-escape, capacity will be zero and level will be off. + //No need to check that construction completed. + return capacity > 0 && this.logLevel.intValue() != offValue; } /** @@ -971,30 +995,19 @@ public boolean isEnabled() { * @see #isEnabled() * @since Angus Mail 2.0.3 */ - public void setEnabled(final boolean enabled) { + public synchronized void setEnabled(final boolean enabled) { checkAccess(); - setEnabled0(enabled); - } - - /** - * Used to enable or disable this handler. - * - * Pushes any buffered records to the email server as normal priority. - * The internal buffer is then cleared. - * - * @param enabled true to enable and false to disable. - * @since Angus Mail 2.0.3 - */ - private synchronized void setEnabled0(final boolean enabled) { if (this.capacity > 0) { //handler is open - this.push(false, ErrorManager.FLUSH_FAILURE); + if (this.size != 0) { + push(false, ErrorManager.FLUSH_FAILURE); + } if (enabled) { - if (disabledLevel != null) { //was disabled + if (this.disabledLevel != null) { //was disabled this.logLevel = this.disabledLevel; this.disabledLevel = null; } } else { - if (disabledLevel == null) { + if (this.disabledLevel == null) { this.disabledLevel = this.logLevel; this.logLevel = Level.OFF; } @@ -1041,6 +1054,8 @@ public void setLevel(final Level newLevel) { */ @Override public Level getLevel() { + //For a this-escape, this value will be OFF. + //No need to check that construction completed. return logLevel; //Volatile access. } @@ -1134,6 +1149,8 @@ public void setFilter(final Filter newFilter) { */ @Override public synchronized String getEncoding() { + //For a this-escape, this value will be null. + //No need to check that construction completed. return this.encoding; } @@ -1304,8 +1321,8 @@ public final synchronized void setComparator(Comparator c) { * @return the capacity. */ public final synchronized int getCapacity() { - assert capacity != Integer.MIN_VALUE && capacity != 0 : capacity; - return Math.abs(capacity); + assert capacity != Integer.MIN_VALUE : capacity; + return capacity != 0 ? Math.abs(capacity) : DEFAULT_CAPACITY; } /** @@ -1314,15 +1331,16 @@ public final synchronized int getCapacity() { * Pushes any buffered records to the email server as normal priority. * The internal buffer is then cleared. * - * @param newCapacity the max number of records. + * @param newCapacity the max number of records. The default capacity of + * 1000 is used if the given capacity is less than one. * @throws SecurityException if a security manager exists and the caller * does not have LoggingPermission("control"). - * @throws IllegalArgumentException is the new capacity is less than one. * @throws IllegalStateException if called from inside a push. * @see #flush() * @since Angus Mail 2.0.3 */ public final synchronized void setCapacity(int newCapacity) { + checkAccess(); setCapacity0(newCapacity); } @@ -1429,6 +1447,7 @@ private void setAuthenticator0(final Authenticator auth) { * @throws IllegalStateException if called from inside a push. */ public final void setMailProperties(Properties props) { + checkAccess(); if (props == null) { final String p = getClass().getName(); props = parseProperties( @@ -1450,13 +1469,18 @@ public final void setMailProperties(Properties props) { * @since Angus Mail 2.0.3 */ private Properties copyOf(Properties props) { - Properties copy = (Properties) props.clone(); //Allow subclass - return Objects.requireNonNull(copy); //Broken subclass + //Allow subclasses however, check that clone contract was followed in + //that a non-null Properties object was returned. + //No need to perform reflexive test or exact class matching tests as + //that doesn't really cause any unexpected failures. + Properties copy = (Properties) props.clone(); + return Objects.requireNonNull(copy, + props.getClass().getName()); } /** - * A private hook to handle overrides when the public method is declared - * non final. See public method for details. + * A private hook to set and validate properties. + * See public method for details. * * @param props a safe properties object. * @return true if verification key was present. @@ -1464,7 +1488,6 @@ private Properties copyOf(Properties props) { */ private boolean setMailProperties0(Properties props) { Objects.requireNonNull(props); - checkAccess(); Session settings; synchronized (this) { if (isWriting) { @@ -1531,6 +1554,7 @@ public final Properties getMailProperties() { * @since Angus Mail 2.0.3 */ public final void setMailEntries(String entries) { + checkAccess(); if (entries == null) { final String p = getClass().getName(); entries = fromLogManager(p.concat(".mailEntries")); @@ -1930,6 +1954,7 @@ public synchronized final void setSubjectFormatter(final Formatter format) { */ @Override protected void reportError(String msg, Exception ex, int code) { + //For a this-escape, the error manager will be the default. try { if (msg != null) { errorManager.error(Level.SEVERE.getName() @@ -1937,19 +1962,31 @@ protected void reportError(String msg, Exception ex, int code) { } else { errorManager.error((String) null, ex, code); } - } catch (RuntimeException | LinkageError GLASSFISH_21258) { + } catch (final RuntimeException | LinkageError GLASSFISH_21258) { + if (ex != null && GLASSFISH_21258 != ex) { + GLASSFISH_21258.addSuppressed(ex); + } reportLinkageError(GLASSFISH_21258, code); + } catch (final ServiceConfigurationError sce) { + if (ex != null) { + sce.addSuppressed(ex); + } + reportConfigurationError(sce, code); } } /** * Checks logging permissions if this handler has been sealed. + * Otherwise, this will check that this object was fully constructed. + * * @throws SecurityException if a security manager exists and the caller * does not have {@code LoggingPermission("control")}. */ private void checkAccess() { if (sealed) { LogManagerProperties.checkLogManagerAccess(); + } else { + throw new SecurityException("this-escape"); } } @@ -1976,7 +2013,8 @@ final String contentTypeOf(CharSequence chunk) { assert in.markSupported() : in.getClass().getName(); return URLConnection.guessContentTypeFromStream(in); } catch (final IOException IOE) { - reportError(IOE.getMessage(), IOE, ErrorManager.FORMAT_FAILURE); + reportError("Unable to guess content type", + IOE, ErrorManager.FORMAT_FAILURE); } } return null; //text/plain @@ -2095,8 +2133,39 @@ private void reportError(Message msg, Exception ex, int code) { } catch (final Exception e) { reportError(toMsgString(e), ex, code); } - } catch (final LinkageError GLASSFISH_21258) { + } catch (LinkageError GLASSFISH_21258) { + if (ex != null) { + GLASSFISH_21258.addSuppressed(ex); + } reportLinkageError(GLASSFISH_21258, code); + } catch (ServiceConfigurationError sce) { + if (ex != null) { + sce.addSuppressed(ex); + } + reportConfigurationError(sce, code); + } + } + + private void reportConfigurationError(Throwable t, int code) { + final Integer idx = MUTEX.get(); + if (idx == null || idx > MUTEX_SERVICE) { + MUTEX.set(MUTEX_SERVICE); + try { + reportError("Unable to load dependencies", + new IllegalStateException(t), code); + } catch (RuntimeException | ServiceConfigurationError + | LinkageError e) { + if (t != null && e != t) { + e.addSuppressed(t); + } + reportLinkageError(e, code); + } finally { + if (idx != null) { + MUTEX.set(idx); + } else { + MUTEX.remove(); + } + } } } @@ -2109,21 +2178,18 @@ private void reportError(Message msg, Exception ex, int code) { * * @param le the linkage error or a RuntimeException. * @param code the ErrorManager code. - * @throws NullPointerException if error is null. * @since JavaMail 1.5.3 */ private void reportLinkageError(final Throwable le, final int code) { - if (le == null) { - throw new NullPointerException(String.valueOf(code)); - } - + assert le != null : code; final Integer idx = MUTEX.get(); if (idx == null || idx > MUTEX_LINKAGE) { MUTEX.set(MUTEX_LINKAGE); try { Thread.currentThread().getUncaughtExceptionHandler() .uncaughtException(Thread.currentThread(), le); - } catch (RuntimeException | LinkageError ignore) { + } catch (RuntimeException | ServiceConfigurationError + | LinkageError ignore) { } finally { if (idx != null) { MUTEX.set(idx); @@ -2223,23 +2289,25 @@ private String contentWithEncoding(String type, String encoding) { * @throws IllegalStateException if called from inside a push. */ private synchronized void setCapacity0(int newCapacity) { - checkAccess(); - if (newCapacity <= 0) { - newCapacity = 1000; - } - if (isWriting) { throw new IllegalStateException(); } + if (this.capacity == 0) { + return; + } + + if (newCapacity <= 0) { + newCapacity = DEFAULT_CAPACITY; + } + if (this.capacity < 0) { //If closed, remain closed. this.capacity = -newCapacity; } else { this.push(false, ErrorManager.FLUSH_FAILURE); this.capacity = newCapacity; - if (this.data != null && this.data.length > newCapacity) { - this.data = Arrays.copyOf(data, newCapacity, LogRecord[].class); - this.matched = Arrays.copyOf(matched, newCapacity); + if (this.data.length > newCapacity) { + initLogRecords(1); } } } @@ -2387,8 +2455,11 @@ private void grow() { newCapacity = capacity; } assert len != capacity : len; - this.data = Arrays.copyOf(data, newCapacity, LogRecord[].class); - this.matched = Arrays.copyOf(matched, newCapacity); + final LogRecord[] d = Arrays.copyOf(data, newCapacity, LogRecord[].class); + final int[] m = Arrays.copyOf(matched, newCapacity); + //Ensure both arrays are created before assigning. + this.data = d; + this.matched = m; } /** @@ -2402,21 +2473,18 @@ private void grow() { * @see #sealed */ private synchronized void init(final Properties props) { - assert this.errorManager != null; - final String p = getClass().getName(); - this.mailProps = new Properties(); //ensure non-null on exception - final Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER); - try { - this.contentTypes = FileTypeMap.getDefaultFileTypeMap(); - } finally { - getAndSetContextClassLoader(ccl); - } + initLogRecords(0); //Ensure non-null even on exception. + LogManagerProperties.checkLogManagerAccess(); + final String p = getClass().getName(); //Assign any custom error manager first so it can detect all failures. + assert this.errorManager != null; //default set before custom object initErrorManager(fromLogManager(p.concat(".errorManager"))); - initCapacity(fromLogManager(p.concat(".capacity"))); - initLevel(fromLogManager(p.concat(".level"))); - initEnabled(fromLogManager(p.concat(".enabled"))); + int cap = parseCapacity(fromLogManager(p.concat(".capacity"))); + Level lvl = parseLevel(fromLogManager(p.concat(".level"))); + boolean enabled = parseEnabled(fromLogManager(p.concat(".enabled"))); + initContentTypes(); + initFilter(fromLogManager(p.concat(".filter"))); this.auth = newAuthenticator(fromLogManager(p.concat(".authenticator"))); @@ -2433,11 +2501,11 @@ private synchronized void init(final Properties props) { initAttachmentFilters(fromLogManager(p.concat(".attachment.filters"))); initAttachmentNames(fromLogManager(p.concat(".attachment.names"))); - //Verification of all of the MailHandler properties starts here - //That means setting new object members goes above this comment. //Entries are always parsed to report any errors. Properties entries = parseProperties(fromLogManager(p.concat(".mailEntries"))); - sealed = true; + + //Any new handler object members should be set above this line + String verify = fromLogManager(p.concat(".verify")); boolean verified; if (props != null) { //Given properties do not fallback to log manager. @@ -2447,14 +2515,29 @@ private synchronized void init(final Properties props) { //.mailEntries should fallback to log manager when verify key not present. verified = setMailProperties0(entries); } else { - checkAccess(); verified = false; } - if (!verified && fromLogManager(p.concat(".verify")) != null) { - verifySettings(initSession()); + //Fallback to top level verify properties if needed. + if (!verified && verify != null) { + try { + verifySettings(initSession()); + } catch (final RuntimeException re) { + reportError("Unable to verify", re, ErrorManager.OPEN_FAILURE); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, ErrorManager.OPEN_FAILURE); + } } intern(); //Show verify warnings first. + + //Mark the handler as fully constructed by setting these fields. + this.capacity = cap; + if (enabled) { + this.logLevel = lvl; + } else { + this.disabledLevel = lvl; + } + sealed = true; } /** @@ -2471,26 +2554,18 @@ private void intern() { Object canidate; Object result; final Map seen = new HashMap<>(); - try { - intern(seen, this.errorManager); - } catch (final SecurityException se) { - reportError(se.getMessage(), se, ErrorManager.OPEN_FAILURE); - } + intern(seen, this.errorManager); - try { - canidate = this.filter; - result = intern(seen, canidate); - if (result != canidate && result instanceof Filter) { - this.filter = (Filter) result; - } + canidate = this.filter; + result = intern(seen, canidate); + if (result != canidate && result instanceof Filter) { + this.filter = (Filter) result; + } - canidate = this.formatter; - result = intern(seen, canidate); - if (result != canidate && result instanceof Formatter) { - this.formatter = (Formatter) result; - } - } catch (final SecurityException se) { - reportError(se.getMessage(), se, ErrorManager.OPEN_FAILURE); + canidate = this.formatter; + result = intern(seen, canidate); + if (result != canidate && result instanceof Formatter) { + this.formatter = (Formatter) result; } canidate = this.subjectFormatter; @@ -2525,10 +2600,12 @@ private void intern() { } } } catch (final Exception skip) { - reportError(skip.getMessage(), skip, ErrorManager.OPEN_FAILURE); + reportError("Unable to deduplcate", skip, ErrorManager.OPEN_FAILURE); } catch (final LinkageError skip) { - reportError(skip.getMessage(), new InvocationTargetException(skip), + reportError("Unable to deduplcate", new InvocationTargetException(skip), ErrorManager.OPEN_FAILURE); + } catch (final ServiceConfigurationError skip) { + reportConfigurationError(skip, ErrorManager.OPEN_FAILURE); } } @@ -2664,7 +2741,7 @@ private void initAttachmentFilters(final String list) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError(Integer.toString(i), E, ErrorManager.OPEN_FAILURE); } } } @@ -2710,7 +2787,7 @@ private void initAttachmentFormaters(final String list) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError(Integer.toString(i), E, ErrorManager.OPEN_FAILURE); a[i] = createSimpleFormatter(); } } else { @@ -2750,7 +2827,7 @@ private void initAttachmentNames(final String list) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError(Integer.toString(i), E, ErrorManager.OPEN_FAILURE); } } else { a[i] = TailNameFormatter.of(toString(attachmentFormatters[i])); @@ -2787,9 +2864,11 @@ private Authenticator newAuthenticator(final String name) { | ClassCastException literalAuth) { a = DefaultAuthenticator.of(name); } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); - } catch (final LinkageError JDK8152515) { - reportLinkageError(JDK8152515, ErrorManager.OPEN_FAILURE); + reportError("Unable to create authenticator", + E, ErrorManager.OPEN_FAILURE); + } catch (final LinkageError GLASSFISH_21258) { + reportLinkageError(GLASSFISH_21258, + ErrorManager.OPEN_FAILURE); } } else { //Authenticator is installed to provide the user name. a = DefaultAuthenticator.of(name); @@ -2804,21 +2883,37 @@ private Authenticator newAuthenticator(final String name) { * @param nameOrNumber the level name or number. * @throws SecurityException if not allowed. */ - private void initLevel(final String nameOrNumber) { + private Level parseLevel(final String nameOrNumber) { assert Thread.holdsLock(this); assert disabledLevel == null : disabledLevel; + Level lvl = Level.WARNING; try { if (!isEmpty(nameOrNumber)) { - logLevel = Level.parse(nameOrNumber); - } else { - logLevel = Level.WARNING; + lvl = Level.parse(nameOrNumber); } } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.OPEN_FAILURE); - logLevel = Level.WARNING; + reportError(nameOrNumber, RE, ErrorManager.OPEN_FAILURE); } + return lvl; + } + + /** + * Creates the internal collection to store log records. + * This method assumes that no log records are currently stored. + * + * @param records the number of records. + * @throws RuntimeException if records is negative. + * @since Angus Mail 2.0.3 + */ + private void initLogRecords(final int records) { + assert this.size == 0 : this.size; + final LogRecord[] d = new LogRecord[records]; + final int[] m = new int[records]; + //Ensure both arrays are created before assigning. + this.data = d; + this.matched = m; } /** @@ -2833,31 +2928,32 @@ private void initLevel(final String nameOrNumber) { * @see #setMailEntries(java.lang.String) */ private Properties parseProperties(String entries) { - if (entries != null) { - final Properties props = new Properties(); - if (!hasValue(entries)) { - return props; - } + if (entries == null) { + return null; + } - /** - * The characters # and ! are used for comment lines in properties - * format. The characters \r or \n are not allowed in WildFly form - * validation however, properties comment characters are allowed. - * Comment lines are useless for this handler therefore, "#!" - * characters are used to represent logical lines and are assumed to - * not be present together in a key or value. - */ - try { - entries = entries.replace("#!", "\r\n"); - //Dynamic cast used so byte code verifier doesn't load StringReader - props.load(Reader.class.cast(new StringReader(entries))); - } catch (IOException | RuntimeException ex) { - reportError(entries, ex, ErrorManager.OPEN_FAILURE); - //Allow a partial load of properties to be set - } - return props; + final Properties props = new Properties(); + if (!hasValue(entries)) { + return props; } - return null; + + /** + * The characters # and ! are used for comment lines in properties + * format. The characters \r or \n are not allowed in WildFly form + * validation however, properties comment characters are allowed. + * Comment lines are useless for this handler therefore, "#!" + * characters are used to represent logical lines and are assumed to + * not be present together in a key or value. + */ + try { + entries = entries.replace("#!", "\r\n"); + //Dynamic cast used so byte code verifier doesn't load StringReader + props.load(Reader.class.cast(new StringReader(entries))); + } catch (IOException | RuntimeException ex) { + reportError(entries, ex, ErrorManager.OPEN_FAILURE); + //Allow a partial load of properties to be set + } + return props; } /** @@ -2867,14 +2963,10 @@ private Properties parseProperties(String entries) { * @param enabled the string false will only disable this handler. * @since Angus Mail 2.0.3 */ - private void initEnabled(final String enabled) { + private boolean parseEnabled(final String enabled) { assert Thread.holdsLock(this); - assert logLevel != null; - assert capacity != 0; //By default the Handler is enabled so only need to disable it on init. - if (hasValue(enabled) && !Boolean.parseBoolean(enabled)) { - setEnabled0(false); - } + return !hasValue(enabled) || Boolean.parseBoolean(enabled); } /** @@ -2894,7 +2986,8 @@ private void initFilter(final String name) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError("Unable to create filter", + E, ErrorManager.OPEN_FAILURE); } } @@ -2904,27 +2997,23 @@ private void initFilter(final String name) { * @param value the capacity value. * @throws SecurityException if not allowed. */ - private void initCapacity(final String value) { + private int parseCapacity(final String value) { assert Thread.holdsLock(this); - final int DEFAULT_CAPACITY = 1000; + int cap = 0; try { if (value != null) { - this.setCapacity0(Integer.parseInt(value)); - } else { - this.setCapacity0(DEFAULT_CAPACITY); + cap = Integer.parseInt(value); } } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.OPEN_FAILURE); + reportError("Unable to set capacity", RE, ErrorManager.OPEN_FAILURE); } - if (capacity <= 0) { - capacity = DEFAULT_CAPACITY; + if (cap <= 0) { + cap = DEFAULT_CAPACITY; } - - this.data = new LogRecord[1]; - this.matched = new int[this.data.length]; + return cap; } /** @@ -2940,7 +3029,7 @@ private void initEncoding(final String e) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (UnsupportedEncodingException | RuntimeException UEE) { - reportError(UEE.getMessage(), UEE, ErrorManager.OPEN_FAILURE); + reportError(e, UEE, ErrorManager.OPEN_FAILURE); } } @@ -2971,8 +3060,8 @@ private ErrorManager defaultErrorManager() { * @param name the error manager class name. * @throws SecurityException if not allowed. */ + @SuppressWarnings("this-escape") private void initErrorManager(final String name) { - assert Thread.holdsLock(this); try { if (name != null) { setErrorManager0(LogManagerProperties.newErrorManager(name)); @@ -2980,7 +3069,8 @@ private void initErrorManager(final String name) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError("Unable to create error manager", + E, ErrorManager.OPEN_FAILURE); } } @@ -3008,7 +3098,8 @@ private void initFormatter(final String name) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError("Unable to create formatter", + E, ErrorManager.OPEN_FAILURE); formatter = createSimpleFormatter(); } } @@ -3030,7 +3121,7 @@ private void initComparator(final String name) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError("Unable to create comparator", E, ErrorManager.OPEN_FAILURE); } } @@ -3042,8 +3133,31 @@ private void initComparatorReverse(final String reverse) { } else { IllegalArgumentException E = new IllegalArgumentException( "No comparator to reverse."); - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError(reverse, E, ErrorManager.OPEN_FAILURE); + } + } + } + + /** + * Gets and assigns the content types for this handler. + * + * @since Angus Mail 2.0.3 + */ + private void initContentTypes() { + try { + Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER); + try { + this.contentTypes = FileTypeMap.getDefaultFileTypeMap(); + } finally { //reset ccl before reporting errors + getAndSetContextClassLoader(ccl); } + } catch (final RuntimeException re) { + reportError("Unable to get default FileTypeMap", + re, ErrorManager.OPEN_FAILURE); + } catch (final LinkageError GLASSFISH_21258) { + reportLinkageError(GLASSFISH_21258, ErrorManager.OPEN_FAILURE); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, ErrorManager.OPEN_FAILURE); } } @@ -3062,7 +3176,7 @@ private void initPushLevel(final String nameOrNumber) { this.pushLevel = Level.OFF; } } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.OPEN_FAILURE); + reportError("Unable to parse push level", RE, ErrorManager.OPEN_FAILURE); } if (this.pushLevel == null) { @@ -3087,7 +3201,7 @@ private void initPushFilter(final String name) { } catch (final SecurityException SE) { throw SE; //Avoid catch all. } catch (final Exception E) { - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError("Unable to create push filter", E, ErrorManager.OPEN_FAILURE); } } @@ -3117,7 +3231,7 @@ private void initSubject(String name) { this.subjectFormatter = TailNameFormatter.of(name); } catch (final Exception E) { this.subjectFormatter = TailNameFormatter.of(name); - reportError(E.getMessage(), E, ErrorManager.OPEN_FAILURE); + reportError("Unable to create subject formatter", E, ErrorManager.OPEN_FAILURE); } } else { //User has forced empty or literal null. this.subjectFormatter = TailNameFormatter.of(name); @@ -3188,6 +3302,8 @@ private void push(final boolean priority, final int code) { } } catch (final LinkageError JDK8152515) { reportLinkageError(JDK8152515, code); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, code); } finally { releaseMutex(); } @@ -3238,7 +3354,7 @@ private void sort() { } } } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.FORMAT_FAILURE); + reportError(comparator.toString(), RE, ErrorManager.FORMAT_FAILURE); } } } @@ -3252,6 +3368,8 @@ private void sort() { * @return null if there are no records or is currently in a push. * Otherwise a new message is created with a formatted message and * attached session. + * @throws ServiceConfigurationError if the session provider fails to + * lookup the provider implementation. */ private Message writeLogRecords(final int code) { try { @@ -3269,7 +3387,7 @@ private Message writeLogRecords(final int code) { } } } catch (final Exception e) { - reportError(e.getMessage(), e, code); + reportError("Unable to create message", e, code); } return null; } @@ -3284,6 +3402,8 @@ private Message writeLogRecords(final int code) { * @throws MessagingException if there is a problem. * @throws IOException if there is a problem. * @throws RuntimeException if there is an unexpected problem. + * @throws ServiceConfigurationError if the session provider fails to + * lookup the provider implementation. * @since JavaMail 1.5.3 */ private Message writeLogRecords0() throws Exception { @@ -3465,6 +3585,8 @@ private boolean verifySettings(final Session session) { } } catch (final LinkageError JDK8152515) { reportLinkageError(JDK8152515, ErrorManager.OPEN_FAILURE); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, ErrorManager.OPEN_FAILURE); } return false; } @@ -3907,10 +4029,17 @@ private void setErrorContent(MimeMessage msg, String verify, Throwable t) { */ private Session updateSession() { assert Thread.holdsLock(this); - final Session settings; + Session settings = null; if (mailProps.getProperty("verify") != null) { - settings = initSession(); - assert settings == session : session; + try { + settings = initSession(); + assert settings == session : session; + } catch (final RuntimeException re) { + reportError("Unable to update session", + re, ErrorManager.OPEN_FAILURE); + } catch (final ServiceConfigurationError sce) { + reportConfigurationError(sce, ErrorManager.OPEN_FAILURE); + } } else { session = null; //Remove old session. settings = null; @@ -3922,6 +4051,10 @@ private Session updateSession() { * Creates a session using a proxy properties object. * * @return the session that was created and assigned. + * @throws IllegalStateException if the session provider fails to lookup the + * provider implementation. + * @throws ServiceConfigurationError if the session provider fails to + * lookup the provider implementation. */ private Session initSession() { assert Thread.holdsLock(this); @@ -3963,10 +4096,17 @@ private void envelopeFor(Message msg, boolean priority) { try { msg.setSentDate(new java.util.Date()); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Sent date not set", ME, ErrorManager.FORMAT_FAILURE); } } + /** + * Creates a new MimeMultipart. + * + * @return a new MimeMultipart + * @throws MessagingException if there is a problem. + * @since Angus Mail 2.0.3 + */ private MimeMultipart createMultipart() throws MessagingException { assert Thread.holdsLock(this); final Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER); @@ -4122,7 +4262,7 @@ private void appendFileName0(final Part part, String chunk) { final String old = part.getFileName(); part.setFileName(old != null ? old.concat(chunk) : chunk); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("File name truncated", ME, ErrorManager.FORMAT_FAILURE); } } @@ -4159,7 +4299,7 @@ private void appendSubject0(final Message msg, String chunk) { ((MimeMessage) msg).setSubject(old != null ? old.concat(chunk) : chunk, MimeUtility.mimeCharset(charset)); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Subject truncated", ME, ErrorManager.FORMAT_FAILURE); } } @@ -4239,7 +4379,8 @@ private void appendContentLang(final MimePart p, final Locale l) { } } } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Content-Language not set", + ME, ErrorManager.FORMAT_FAILURE); } } @@ -4258,7 +4399,8 @@ private void setAcceptLang(final Part p) { p.setHeader("Accept-Language", lang); } } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Accept-Language not set", + ME, ErrorManager.FORMAT_FAILURE); } } @@ -4334,7 +4476,7 @@ private String head(final Formatter f) { try { return f.getHead(this); } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.FORMAT_FAILURE); + reportError("head", RE, ErrorManager.FORMAT_FAILURE); return ""; } } @@ -4350,7 +4492,7 @@ private String format(final Formatter f, final LogRecord r) { try { return f.format(r); } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.FORMAT_FAILURE); + reportError("format", RE, ErrorManager.FORMAT_FAILURE); return ""; } } @@ -4366,7 +4508,7 @@ private String tail(final Formatter f, final String def) { try { return f.getTail(this); } catch (final RuntimeException RE) { - reportError(RE.getMessage(), RE, ErrorManager.FORMAT_FAILURE); + reportError("tail", RE, ErrorManager.FORMAT_FAILURE); return def; } } @@ -4387,7 +4529,7 @@ private void setMailer(final Message msg) { try { value = MimeUtility.encodeText(k.getName()); } catch (final UnsupportedEncodingException E) { - reportError(E.getMessage(), E, ErrorManager.FORMAT_FAILURE); + reportError(k.getName(), E, ErrorManager.FORMAT_FAILURE); value = k.getName().replaceAll("[^\\x00-\\x7F]", "\uu001A"); } value = MimeUtility.fold(10, mail.getName() + " using the " @@ -4395,7 +4537,8 @@ private void setMailer(final Message msg) { } msg.setHeader("X-Mailer", value); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("X-Mailer not set", + ME, ErrorManager.FORMAT_FAILURE); } } @@ -4410,7 +4553,8 @@ private void setPriority(final Message msg) { msg.setHeader("Priority", "urgent"); msg.setHeader("X-Priority", "2"); //High } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Importance and priority not set", + ME, ErrorManager.FORMAT_FAILURE); } } @@ -4429,7 +4573,8 @@ private void setIncompleteCopy(final Message msg) { try { msg.setHeader("Incomplete-Copy", ""); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Incomplete-Copy not set", + ME, ErrorManager.FORMAT_FAILURE); } } @@ -4445,7 +4590,8 @@ private void setAutoSubmitted(final Message msg) { try { //RFC 3834 (5.2) msg.setHeader("auto-submitted", "auto-generated"); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("auto-submitted not set", + ME, ErrorManager.FORMAT_FAILURE); } } } @@ -4472,7 +4618,8 @@ private void setFrom(final Message msg) { //to fail. Assume the user wants to omit the from address //header. } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("From address not set", + ME, ErrorManager.FORMAT_FAILURE); setDefaultFrom(msg); } } else { @@ -4489,7 +4636,8 @@ private void setDefaultFrom(final Message msg) { try { msg.setFrom(); } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Default from address not set", + ME, ErrorManager.FORMAT_FAILURE); } } @@ -4518,7 +4666,7 @@ private void setDefaultRecipient(final Message msg, } } } catch (MessagingException | RuntimeException ME) { - reportError("Unable to compute a default recipient.", + reportError("Default recipient not set", ME, ErrorManager.FORMAT_FAILURE); } } @@ -4537,7 +4685,8 @@ private void setReplyTo(final Message msg) { msg.setReplyTo(address); } } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Reply-To address not set", + ME, ErrorManager.FORMAT_FAILURE); } } } @@ -4563,7 +4712,7 @@ private void setSender(final Message msg) { } } } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError("Sender not set", ME, ErrorManager.FORMAT_FAILURE); } } } @@ -4600,7 +4749,7 @@ private boolean setRecipient(final Message msg, msg.setRecipients(type, address); } } catch (final MessagingException ME) { - reportError(ME.getMessage(), ME, ErrorManager.FORMAT_FAILURE); + reportError(key, ME, ErrorManager.FORMAT_FAILURE); } } return containsKey; @@ -4734,7 +4883,7 @@ private String getLocalHost(final Service s) { } catch (SecurityException | NoSuchMethodException | LinkageError ignore) { } catch (final Exception ex) { - reportError(s.toString(), ex, ErrorManager.OPEN_FAILURE); + reportError(String.valueOf(s), ex, ErrorManager.OPEN_FAILURE); } return null; } diff --git a/providers/angus-mail/src/test/java/org/eclipse/angus/mail/util/logging/MailHandlerTest.java b/providers/angus-mail/src/test/java/org/eclipse/angus/mail/util/logging/MailHandlerTest.java index cbd2005..c5bfd04 100644 --- a/providers/angus-mail/src/test/java/org/eclipse/angus/mail/util/logging/MailHandlerTest.java +++ b/providers/angus-mail/src/test/java/org/eclipse/angus/mail/util/logging/MailHandlerTest.java @@ -506,14 +506,13 @@ private void testLoggable(Level lvl, LogRecord record) { instance.setErrorManager(em); instance.setLevel(lvl); - boolean result = false; boolean expect = true; if (record == null || record.getLevel().intValue() < lvl.intValue() || Level.OFF.intValue() == lvl.intValue()) { expect = false; } - result = instance.isLoggable(record); + boolean result = instance.isLoggable(record); assertEquals(lvl.getName(), expect, result); instance.setLevel(Level.INFO); @@ -1141,14 +1140,14 @@ public void testSingleSortComparator() { } InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Throwable t : em.exceptions) { - if (isConnectOrTimeout(t)) { - continue; - } else { + if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -1165,19 +1164,21 @@ public void testSingleSortViolateContract() { boolean seenError = false; InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Throwable t : em.exceptions) { if (isConnectOrTimeout(t)) { continue; - } else if (t.getClass() == IllegalArgumentException.class + } + if (t.getClass() == IllegalArgumentException.class && t.getMessage().contains(instance.getComparator() .getClass().getName())) { seenError = true; //See Arrays.sort(T[], Comparator) continue; //expect. - } else { - dump(t); - fail(t.toString()); } + dump(t); + failed = true; } + assertFalse(failed); assertTrue("Exception was not thrown.", seenError); assertFalse(em.exceptions.isEmpty()); } @@ -1209,18 +1210,19 @@ private void testThrowComparator(int records) { InternalErrorManager em = internalErrorManagerFrom(instance); boolean seenError = false; + boolean failed = false; for (Throwable t : em.exceptions) { if (isConnectOrTimeout(t)) { continue; - } else if (t.getClass() == RuntimeException.class) { + } + if (t.getClass() == RuntimeException.class) { seenError = true; continue; //expect. - } else { - dump(t); - fail(t.toString()); } + dump(t); + failed = true; } - + assertFalse(failed); if (records == 0) { assertEquals(true, em.exceptions.isEmpty()); } else { @@ -1593,12 +1595,14 @@ public void testStatefulFilter() { } h.close(); assertEquals(MAX_RECORDS, cf.count); + boolean failed = false; for (Exception exception : em.exceptions) { if (!isConnectOrTimeout(exception)) { dump(exception); - fail(String.valueOf(exception)); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -1625,12 +1629,14 @@ public void testStatefulAttachmentFilter() { assertEquals(MAX_RECORDS, negativeOne.count); assertEquals(MAX_RECORDS, one.count); assertEquals(MAX_RECORDS, two.count); + boolean failed = false; for (Exception exception : em.exceptions) { if (!isConnectOrTimeout(exception)) { dump(exception); - fail(String.valueOf(exception)); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -1666,12 +1672,14 @@ private void testStatefulAttachmentFilter(boolean clear) { assertEquals(MAX_RECORDS, cf.count); assertEquals(MAX_RECORDS, one.count); + boolean failed = false; for (Exception exception : em.exceptions) { if (!isConnectOrTimeout(exception)) { dump(exception); - fail(String.valueOf(exception)); + failed = false; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -1694,12 +1702,14 @@ public void testStatefulPushFilter() { h.publish(r); h.close(); assertEquals(1, cf.count); + boolean failed = false; for (Exception exception : em.exceptions) { if (!isConnectOrTimeout(exception)) { dump(exception); - fail(String.valueOf(exception)); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -1748,12 +1758,14 @@ public boolean isLoggable(LogRecord record) { assertEquals(1, two.count); assertEquals(1, push.count); } + boolean failed = false; for (Exception exception : em.exceptions) { if (!isConnectOrTimeout(exception)) { dump(exception); - fail(String.valueOf(exception)); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -2096,14 +2108,16 @@ public String getTail(Handler h) { } instance.flush(); + boolean failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if ((t instanceof MessagingException == false) && (t instanceof IllegalStateException == false)) { dump(t); - fail(String.valueOf(t)); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -2366,13 +2380,15 @@ private void testCloseContextClassLoader0() { instance.close(); } + boolean failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); } @Test @@ -2523,18 +2539,20 @@ public void testLevelBeforeClose() { instance.setFormatter(new LevelCheckingFormatter(expect)); instance.close(); + boolean failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (t instanceof MessagingException) { if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } else { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -2550,18 +2568,20 @@ public void testLevelAfterClose() { assertEquals(Level.OFF, instance.getLevel()); instance.close(); + boolean failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (t instanceof MessagingException) { if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } else { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -2575,6 +2595,7 @@ public void testLogManagerReset() throws IOException { manager.reset(); + boolean failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (t instanceof MessagingException) { @@ -2583,17 +2604,19 @@ public void testLogManagerReset() throws IOException { } if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } else { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); instance = startLogManagerReset("local"); em = internalErrorManagerFrom(instance); + failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (t instanceof MessagingException) { @@ -2602,16 +2625,18 @@ public void testLogManagerReset() throws IOException { } if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } else { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); manager.reset(); + failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (t instanceof MessagingException) { @@ -2620,13 +2645,14 @@ public void testLogManagerReset() throws IOException { } if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } else { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); String[] noVerify = new String[]{null, "", "null"}; for (int v = 0; v < noVerify.length; v++) { @@ -2666,16 +2692,18 @@ public void testLogManagerReset() throws IOException { //Allow the LogManagerProperties to copy on a bad enum type. boolean foundIllegalArg = false; + failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if (t instanceof IllegalArgumentException) { foundIllegalArg = true; } else if (t instanceof RuntimeException) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertTrue(foundIllegalArg); assertFalse(em.exceptions.isEmpty()); } finally { @@ -3229,14 +3257,15 @@ protected void error(MimeMessage msg, Throwable t, int code) { target.close(); + boolean failed = false; InternalErrorManager em = internalErrorManagerFrom(target); for (Exception t : em.exceptions) { - if (isConnectOrTimeout(t)) { - continue; + if (!isConnectOrTimeout(t)) { + dump(t); + failed = true; } - dump(t); - fail(t.toString()); } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { Locale.setDefault(l); @@ -3347,14 +3376,15 @@ private void testContentLangInfer(MailHandler target, String logPrefix, String b target.close(); + boolean failed = false; InternalErrorManager em = internalErrorManagerFrom(target); for (Exception t : em.exceptions) { - if (isConnectOrTimeout(t)) { - continue; + if (!isConnectOrTimeout(t)) { + dump(t); + failed = true; } - dump(t); - fail(t.toString()); } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -3470,14 +3500,15 @@ protected void error(MimeMessage msg, Throwable t, int code) { target.close(); + boolean failed = false; InternalErrorManager em = internalErrorManagerFrom(target); for (Exception t : em.exceptions) { - if (isConnectOrTimeout(t)) { - continue; + if (!isConnectOrTimeout(t)) { + dump(t); + failed = true; } - dump(t); - fail(t.toString()); } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -3883,15 +3914,15 @@ public void testMailProperties() throws Exception { props.setProperty("mail.to", "localhost@localdomain"); instance.setMailProperties(props); instance.flush(); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; - if (isConnectOrTimeout(t)) { - continue; - } else { + if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); props.setProperty("mail.from", "localhost@localdomain"); @@ -3903,17 +3934,16 @@ public void testMailProperties() throws Exception { instance.publish(new LogRecord(Level.SEVERE, "test")); instance.close(); - int failed = 0; + failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException || isConnectOrTimeout(t)) { continue; - } else { - dump(t); - failed++; } + dump(t); + failed = true; } - assertEquals(0, failed); + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -3936,6 +3966,7 @@ public void testInitMailEntriesNullMailProperties() throws Exception { assertEquals("localhost@localdomain", stored.getProperty("mail.from")); assertEquals("local",stored.getProperty("verify")); + boolean failed = false; for (Exception e : em.exceptions) { if (e instanceof AddressException) { if (e.toString().contains("badAddress")) { @@ -3943,8 +3974,9 @@ public void testInitMailEntriesNullMailProperties() throws Exception { } } dump(e); - fail(e.toString()); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); target.setMailProperties((Properties) null); @@ -3952,6 +3984,7 @@ public void testInitMailEntriesNullMailProperties() throws Exception { assertEquals("localhost@localdomain", stored.getProperty("mail.from")); assertEquals("local", stored.getProperty("verify")); + failed = false; for (Exception e : em.exceptions) { if (e instanceof AddressException) { if (e.toString().contains("badAddress")) { @@ -3959,12 +3992,14 @@ public void testInitMailEntriesNullMailProperties() throws Exception { } } dump(e); - fail(e.toString()); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); target = new MailHandler((Properties) null); em = internalErrorManagerFrom(target); + failed = false; for (Exception e : em.exceptions) { if (e instanceof AddressException) { if (e.toString().contains("badAddress")) { @@ -3972,8 +4007,9 @@ public void testInitMailEntriesNullMailProperties() throws Exception { } } dump(e); - fail(e.toString()); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); stored = target.getMailProperties(); @@ -4013,6 +4049,7 @@ public void testInitMailEntriesNullSetMailEntries() throws Exception { InternalErrorManager em = internalErrorManagerFrom(target); target.setMailEntries((String) null); Properties stored = target.getMailProperties(); + boolean failed = false; for (Exception e : em.exceptions) { if (e instanceof AddressException) { if (e.toString().contains("badAddress")) { @@ -4020,8 +4057,9 @@ public void testInitMailEntriesNullSetMailEntries() throws Exception { } } dump(e); - fail(e.toString()); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); assertEquals("localhost@localdomain", stored.getProperty("mail.from")); @@ -4346,16 +4384,16 @@ private List
asList(Address... a) { instance.setMailProperties(addresses); instance.close(); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (isConnectOrTimeout(t) || t instanceof SendFailedException) { continue; - } else { - dump(t); - fail(t.toString()); } + dump(t); + failed = true; } - + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -4374,6 +4412,7 @@ public void testInvalidDefaultRecipient() throws Exception { instance.setMailProperties(props); instance.close(); InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { if (exception instanceof MessagingException) { if (exception instanceof AddressException @@ -4390,8 +4429,9 @@ public void testInvalidDefaultRecipient() throws Exception { } } dump(exception); - fail(exception.toString()); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -4791,19 +4831,21 @@ public void testAttachmentFilterSwapBeforePush() { instance.close(); int seenFormat = 0; + boolean failed = false; for (Exception exception : em.exceptions) { if (exception instanceof MessagingException) { continue; - } else if (exception instanceof RuntimeException + } + if (exception instanceof RuntimeException && exception.getMessage().contains(instance.getFilter().toString()) && exception.getMessage().contains(Arrays.asList(instance.getAttachmentFilters()).toString())) { seenFormat++; continue; //expected. - } else { - fail(String.valueOf(exception)); } + failed = true; } assertTrue("No format error", seenFormat > 0); + assertFalse(failed); } @Test @@ -4959,14 +5001,16 @@ private void testPushFilterReentrance(int records, int cap) { } instance.close(); + boolean failed = false; for (Exception exception : em.exceptions) { Throwable t = exception; if ((t instanceof MessagingException == false) && (t instanceof IllegalStateException == false)) { dump(t); - fail(String.valueOf(t)); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { logger.removeHandler(instance); @@ -5327,14 +5371,16 @@ public void testVerifyErrorManager() throws Exception { //ensure VerifyErrorManager was installed. assertEquals(VerifyErrorManager.class, em.getClass()); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (!isConnectOrTimeout(t)) { dump(t); - fail(t.toString()); + failed = false; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); instance.close(); } finally { @@ -5466,6 +5512,7 @@ public void testIntern() throws Exception { assertSame(names[5], names[6]); InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof IllegalArgumentException @@ -5473,7 +5520,9 @@ public void testIntern() throws Exception { continue; } dump(t); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } @@ -5505,6 +5554,7 @@ public void testInternNonDiscriminating() throws Exception { instance.close(); InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof IllegalArgumentException @@ -5512,7 +5562,9 @@ public void testInternNonDiscriminating() throws Exception { continue; } dump(t); + failed = true; } + assertFalse(failed); assertEquals(2, em.exceptions.size()); } @@ -5535,7 +5587,6 @@ public void testComparatorReverse() throws Exception { for (Exception exception : em.exceptions) { final Throwable t = exception; dump(t); - fail(t.toString()); } assertTrue(em.exceptions.isEmpty()); @@ -5553,7 +5604,6 @@ public void testComparatorReverse() throws Exception { for (Exception exception : em.exceptions) { final Throwable t = exception; dump(t); - fail(t.toString()); } assertTrue(em.exceptions.isEmpty()); @@ -5571,7 +5621,6 @@ public void testComparatorReverse() throws Exception { for (Exception exception : em.exceptions) { final Throwable t = exception; dump(t); - fail(t.toString()); } assertTrue(em.exceptions.isEmpty()); @@ -5585,15 +5634,16 @@ public void testComparatorReverse() throws Exception { instance = new MailHandler(); instance.close(); em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof IllegalArgumentException) { continue; } dump(t); - fail(t.toString()); + failed = true; } - + assertFalse(failed); assertFalse(IllegalArgumentException.class.getName(), em.exceptions.isEmpty()); @@ -5602,15 +5652,16 @@ public void testComparatorReverse() throws Exception { instance = new MailHandler(); instance.close(); em = internalErrorManagerFrom(instance); + failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof IllegalArgumentException) { continue; } dump(t); - fail(t.toString()); + failed = true; } - + assertFalse(failed); assertFalse(IllegalArgumentException.class.getName(), em.exceptions.isEmpty()); @@ -5619,15 +5670,16 @@ public void testComparatorReverse() throws Exception { instance = new MailHandler(); instance.close(); em = internalErrorManagerFrom(instance); + failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof IllegalArgumentException) { continue; } dump(t); - fail(t.toString()); + failed = true; } - + assertFalse(failed); assertFalse(IllegalArgumentException.class.getName(), em.exceptions.isEmpty()); } finally { @@ -5657,13 +5709,15 @@ public void testVerifyLogManager() throws Exception { assertEquals(InternalErrorManager.class, em.getClass()); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); instance.close(); @@ -5677,13 +5731,15 @@ public void testVerifyLogManager() throws Exception { assertEquals(InternalErrorManager.class, em.getClass()); + failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); instance.close(); @@ -5697,6 +5753,7 @@ public void testVerifyLogManager() throws Exception { assertEquals(InternalErrorManager.class, em.getClass()); + failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (isConnectOrTimeout(t)) { @@ -5704,9 +5761,10 @@ public void testVerifyLogManager() throws Exception { } if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); instance.close(); @@ -5719,17 +5777,19 @@ public void testVerifyLogManager() throws Exception { assertEquals(InternalErrorManager.class, em.getClass()); + failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException) { continue; - } else if (isConnectOrTimeout(t)) { + } + if (isConnectOrTimeout(t)) { continue; - } else { - dump(t); - fail(t.toString()); } + dump(t); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { manager.reset(); @@ -5748,13 +5808,15 @@ public void testVerifyProperties() throws Exception { instance.setErrorManager(em); instance.setMailProperties(props); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); } finally { instance.close(); } @@ -5766,13 +5828,15 @@ public void testVerifyProperties() throws Exception { instance.setErrorManager(em); instance.setMailProperties(props); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); } finally { instance.close(); } @@ -5784,6 +5848,7 @@ public void testVerifyProperties() throws Exception { instance.setErrorManager(em); instance.setMailProperties(props); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (isConnectOrTimeout(t)) { @@ -5791,9 +5856,10 @@ public void testVerifyProperties() throws Exception { } if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); } finally { instance.close(); } @@ -5805,6 +5871,7 @@ public void testVerifyProperties() throws Exception { instance.setErrorManager(em); instance.setMailProperties(props); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (isConnectOrTimeout(t)) { @@ -5812,9 +5879,10 @@ public void testVerifyProperties() throws Exception { } if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); } finally { instance.close(); } @@ -5826,17 +5894,19 @@ public void testVerifyProperties() throws Exception { instance.setErrorManager(em); instance.setMailProperties(props); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException) { continue; - } else if (isConnectOrTimeout(t)) { + } + if (isConnectOrTimeout(t)) { continue; - } else { - dump(t); - fail(t.toString()); } + dump(t); + failed = true; } + assertFalse(failed); } finally { instance.close(); } @@ -5863,13 +5933,15 @@ public void testVerifyPropertiesConstructor() throws Exception { try { InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { instance.close(); @@ -5887,13 +5959,15 @@ public void testVerifyPropertiesConstructor() throws Exception { try { InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { instance.close(); @@ -5904,7 +5978,7 @@ public void testVerifyPropertiesConstructor() throws Exception { instance = new MailHandler(props); try { InternalErrorManager em = internalErrorManagerFrom(instance); - + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (isConnectOrTimeout(t)) { @@ -5912,9 +5986,10 @@ public void testVerifyPropertiesConstructor() throws Exception { } if (t instanceof AddressException == false) { dump(t); - fail(t.toString()); + failed = true; } } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { instance.close(); @@ -5925,17 +6000,19 @@ public void testVerifyPropertiesConstructor() throws Exception { try { InternalErrorManager em = internalErrorManagerFrom(instance); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof AddressException) { continue; - } else if (isConnectOrTimeout(t)) { + } + if (isConnectOrTimeout(t)) { continue; - } else { - dump(t); - fail(t.toString()); } + dump(t); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { instance.close(); @@ -6167,13 +6244,16 @@ public void testInitAttachmentFilters() throws Exception { target = new MailHandler(); try { em = internalErrorManagerFrom(target); + boolean failed = false; for (Exception exception : em.exceptions) { final Throwable t = exception; if (t instanceof IndexOutOfBoundsException) { continue; } dump(t); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { target.close(); @@ -6542,6 +6622,7 @@ private void testInitException(Properties props) throws Exception { final MailHandler target = new MailHandler(); try { InternalErrorManager em = internalErrorManagerFrom(target); + boolean failed = false; next: for (Exception t : em.exceptions) { for (Throwable cause = t; cause != null; cause = cause.getCause()) { @@ -6550,8 +6631,9 @@ private void testInitException(Properties props) throws Exception { } } dump(t); - fail(t.toString()); + failed = true; } + assertFalse(failed); assertFalse(em.exceptions.isEmpty()); } finally { target.close(); @@ -6897,17 +6979,17 @@ private void initGoodTest(Class type, assertEquals(EmptyFormatter.class, h.getSubject().getClass()); assertEquals(EmptyAuthenticator.class, h.getAuthenticator().getClass()); assertEquals(3, h.getAttachmentFormatters().length); - assertTrue(null != h.getAttachmentFormatters()[0]); - assertTrue(null != h.getAttachmentFormatters()[1]); - assertTrue(null != h.getAttachmentFormatters()[2]); + assertNotNull(h.getAttachmentFormatters()[0]); + assertNotNull(h.getAttachmentFormatters()[1]); + assertNotNull(h.getAttachmentFormatters()[2]); assertEquals(3, h.getAttachmentFilters().length); - assertEquals(null, h.getAttachmentFilters()[0]); + assertNull(h.getAttachmentFilters()[0]); assertEquals(ThrowFilter.class, h.getAttachmentFilters()[1].getClass()); assertEquals(ThrowFilter.class, h.getAttachmentFilters()[2].getClass()); assertEquals(3, h.getAttachmentNames().length); - assertTrue(null != h.getAttachmentNames()[0]); - assertTrue(null != h.getAttachmentNames()[1]); - assertTrue(null != h.getAttachmentNames()[2]); + assertNotNull(h.getAttachmentNames()[0]); + assertNotNull(h.getAttachmentNames()[1]); + assertNotNull(h.getAttachmentNames()[2]); InternalErrorManager em = internalErrorManagerFrom(h); for (Exception exception : em.exceptions) { @@ -7016,12 +7098,10 @@ private void initBadTest(Class type, h = type.getConstructor(types).newInstance(params); System.err.flush(); result = oldErrors.toString(encoding).trim(); - int index = result.indexOf(ErrorManager.class.getName() + ": " - + ErrorManager.OPEN_FAILURE + ": " + Level.SEVERE.getName() - + ": InvalidErrorManager"); - assertTrue(index > -1); - assertTrue(result.indexOf( - "java.lang.ClassNotFoundException: InvalidErrorManager") > index); + assertTrue(result.startsWith(ErrorManager.class.getName() + ": " + + ErrorManager.OPEN_FAILURE + ": " + Level.SEVERE.getName())); + assertTrue(result, result.contains( + "java.lang.ClassNotFoundException: InvalidErrorManager")); oldErrors.reset(); } finally { System.setErr(err); @@ -7029,38 +7109,40 @@ private void initBadTest(Class type, assert h != null; assertEquals(ErrorManager.class, h.getErrorManager().getClass()); - assertTrue(h.getCapacity() != 10); - assertTrue(h.getCapacity() != -10); + assertNotEquals(10, h.getCapacity()); + assertNotEquals(-10, h.getCapacity()); assertEquals(Level.WARNING, h.getLevel()); - assertEquals(null, h.getFilter()); + assertNull( h.getFilter()); assertEquals(SimpleFormatter.class, h.getFormatter().getClass()); assertEquals(Level.OFF, h.getPushLevel()); - assertEquals(null, h.getPushFilter()); + assertNull(h.getPushFilter()); assertNull(h.getComparator()); - assertEquals(null, h.getEncoding()); + assertNull(h.getEncoding()); assertEquals(ThrowFilter.class.getName(), h.getSubject().toString()); PasswordAuthentication pa = passwordAuthentication(h.getAuthenticator(), "user"); assertEquals("user", pa.getUserName()); assertEquals("password", pa.getPassword()); assertEquals(3, h.getAttachmentFormatters().length); - assertTrue(null != h.getAttachmentFormatters()[0]); - assertTrue(null != h.getAttachmentFormatters()[1]); - assertTrue(null != h.getAttachmentFormatters()[2]); + assertNotNull(h.getAttachmentFormatters()[0]); + assertNotNull(h.getAttachmentFormatters()[1]); + assertNotNull(h.getAttachmentFormatters()[2]); assertEquals(3, h.getAttachmentFilters().length); - assertTrue(null == h.getAttachmentFilters()[0]); - assertTrue(null == h.getAttachmentFilters()[1]); - assertTrue(null != h.getAttachmentFilters()[2]); + assertNull(h.getAttachmentFilters()[0]); + assertNull(h.getAttachmentFilters()[1]); + assertNotNull(h.getAttachmentFilters()[2]); assertEquals(ThrowFilter.class, h.getAttachmentFilters()[2].getClass()); assertEquals(3, h.getAttachmentNames().length); - assertTrue(null != h.getAttachmentNames()[0]); - assertTrue(null != h.getAttachmentNames()[1]); - assertTrue(null != h.getAttachmentNames()[2]); + assertNotNull(h.getAttachmentNames()[0]); + assertNotNull(h.getAttachmentNames()[1]); + assertNotNull(h.getAttachmentNames()[2]); assertEquals(XMLFormatter.class, h.getAttachmentNames()[2].getClass()); h.close(); } private static boolean isConnectOrTimeout(Throwable t) { - if (t instanceof MessagingException) { + if (t == null) { + return false; + } else if (t instanceof MessagingException) { Throwable cause = t.getCause(); if (cause == null) { //GNU JavaMail doesn't support 1.4 chaining. cause = ((MessagingException) t).getNextException();