Skip to content
This repository was archived by the owner on Aug 20, 2025. It is now read-only.

Commit f6a31c6

Browse files
committed
MailHandler verify should load additional content handlers - Bug K7506
MailHandlerTest add content type of formatter test. MailHandlerDemo correct javadoc example. (From Jason)
1 parent 8050d86 commit f6a31c6

4 files changed

Lines changed: 139 additions & 20 deletions

File tree

doc/release/CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ K 7378 Deadlock in IMAPFolder.doProtocolCommand()
3232
K 7471 InternetAddress.getLocalAddress should use
3333
InetAddress.getCanonicalHostName
3434
K 7472 Store finalizers should not talk to server
35+
K 7506 MailHandler verify should load additional content handlers
3536
K 7512 NullPointerException if SASL is enabled on Android
3637
K 7513 write timeouts don't work with SSL on Android
3738

logging/src/main/java/MailHandlerDemo.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
/**
5050
* Demo for the different configurations for the MailHandler. If the logging
5151
* properties file or class is not specified then this demo will apply some
52-
* default settings to store emails in the users temp dir.
52+
* default settings to store emails in the user's temp directory.
5353
*
5454
* @author Jason Mehrens
5555
*/
@@ -440,9 +440,8 @@ private static void initWithPushFilter() {
440440
* com.sun.mail.util.logging.MailHandler.level=ALL
441441
* java.util.logging.MemoryHandler.level=ALL
442442
* java.util.logging.MemoryHandler.push=WARNING
443-
* com.sun.mail.util.logging.MailHandler.subject=Push on MessagingException demo
444-
* com.sun.mail.util.logging.MailHandler.pushLevel=ALL
445-
* com.sun.mail.util.logging.MailHandler.pushFilter=MailHandlerDemo$MessageErrorsFilter
443+
* com.sun.mail.util.logging.MailHandler.subject=Push only demo
444+
* com.sun.mail.util.logging.MailHandler.pushLevel=WARNING
446445
* ##
447446
* </code>
448447
*/
@@ -658,4 +657,12 @@ private static String getConfigLocation() {
658657
}
659658
return file;
660659
}
660+
661+
/**
662+
* No objects are allowed.
663+
* @throws IllegalAccessException always.
664+
*/
665+
private MailHandlerDemo() throws IllegalAccessException {
666+
throw new IllegalAccessException();
667+
}
661668
}

mail/src/main/java/com/sun/mail/util/logging/MailHandler.java

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -384,16 +384,17 @@ public class MailHandler extends Handler {
384384
* prepared to deal with unexpected null values since the
385385
* WebappClassLoader.clearReferencesThreadLocals() and
386386
* InnocuousThread.eraseThreadLocals() can remove thread local values.
387-
* The MUTEX has 4 states:
387+
* The MUTEX has 5 states:
388388
* 1. A null value meaning default state of not publishing.
389389
* 2. MUTEX_PUBLISH on first entry of a push or publish.
390390
* 3. The index of the first filter to accept a log record.
391391
* 4. MUTEX_REPORT when cycle of records is detected.
392+
* 5. MUTEXT_LINKAGE when a linkage error is reported.
392393
*/
393394
private static final ThreadLocal<Integer> MUTEX = new ThreadLocal<Integer>();
394395
/**
395396
* The marker object used to report a publishing state.
396-
* This must be less than the body filter index.
397+
* This must be less than the body filter index (-1).
397398
*/
398399
private static final Integer MUTEX_PUBLISH = -2;
399400
/**
@@ -1632,6 +1633,39 @@ final String contentTypeOf(String head) {
16321633
return null; //text/plain
16331634
}
16341635

1636+
/**
1637+
* Determines the mimeType of a formatter by the class name. This method
1638+
* avoids calling getHead and getTail of content formatters during verify
1639+
* because they might trigger side effects or excessive work. The name
1640+
* formatters and subject are usually safe to call.
1641+
* Package-private for unit testing.
1642+
*
1643+
* @param f the formatter or null.
1644+
* @return return the mime type or text/plain.
1645+
* @since JavaMail 1.5.6
1646+
*/
1647+
final String contentTypeOf(final Formatter f) {
1648+
if (f != null) {
1649+
for (Class<?> k = f.getClass(); k != Formatter.class;
1650+
k = k.getSuperclass()) {
1651+
String name = k.getName().toLowerCase(Locale.ENGLISH);
1652+
for (int idx = name.indexOf('$') + 1;
1653+
(idx = name.indexOf("ml", idx)) > -1; idx += 2) {
1654+
if (idx > 0) {
1655+
if (name.charAt(idx - 1) == 'x') {
1656+
return "application/xml";
1657+
}
1658+
if (idx > 1 && name.charAt(idx - 2) == 'h'
1659+
&& name.charAt(idx - 1) == 't') {
1660+
return "text/html";
1661+
}
1662+
}
1663+
}
1664+
}
1665+
}
1666+
return "text/plain";
1667+
}
1668+
16351669
/**
16361670
* Determines if the given throwable is a no content exception. It is
16371671
* assumed Transport.sendMessage will call Message.writeTo so we need to
@@ -1677,12 +1711,14 @@ final boolean isMissingContent(Message msg, Throwable t) {
16771711
*/
16781712
@SuppressWarnings("UseSpecificCatch")
16791713
private void reportError(Message msg, Exception ex, int code) {
1680-
try { //Use direct call so we do not prefix raw email.
1681-
errorManager.error(toRawString(msg), ex, code);
1682-
} catch (final RuntimeException re) {
1683-
reportError(toMsgString(re), ex, code);
1684-
} catch (final Exception e) {
1685-
reportError(toMsgString(e), ex, code);
1714+
try {
1715+
try { //Use direct call so we do not prefix raw email.
1716+
errorManager.error(toRawString(msg), ex, code);
1717+
} catch (final RuntimeException re) {
1718+
reportError(toMsgString(re), ex, code);
1719+
} catch (final Exception e) {
1720+
reportError(toMsgString(e), ex, code);
1721+
}
16861722
} catch (final LinkageError GLASSFISH_21258) {
16871723
reportLinkageError(GLASSFISH_21258, code);
16881724
}
@@ -1798,7 +1834,7 @@ private String contentWithEncoding(String type, String encoding) {
17981834
* Sets the capacity for this handler. This method is kept private
17991835
* because we would have to define a public policy for when the size is
18001836
* greater than the capacity.
1801-
* I.E. do nothing, flush now, truncate now, push now and resize.
1837+
* E.G. do nothing, flush now, truncate now, push now and resize.
18021838
* @param newCapacity the max number of records.
18031839
* @throws SecurityException if a security manager exists and the
18041840
* caller does not have <tt>LoggingPermission("control")</tt>.
@@ -2998,9 +3034,19 @@ private void verifySettings0(Session session, String verify) {
29983034
}
29993035

30003036
//Perform all of the copy actions first.
3037+
String[] atn;
30013038
synchronized (this) { //Create the subject.
30023039
appendSubject(abort, head(subjectFormatter));
30033040
appendSubject(abort, tail(subjectFormatter, ""));
3041+
atn = new String[attachmentNames.length];
3042+
for (int i = 0; i < atn.length; ++i) {
3043+
atn[i] = head(attachmentNames[i]);
3044+
if (atn[i].length() == 0) {
3045+
atn[i] = tail(attachmentNames[i], "");
3046+
} else {
3047+
atn[i] = atn[i].concat(tail(attachmentNames[i], ""));
3048+
}
3049+
}
30043050
}
30053051

30063052
setIncompleteCopy(abort); //Original body part is never added.
@@ -3151,13 +3197,29 @@ private void verifySettings0(Session session, String verify) {
31513197
try { //Verify that the DataHandler can be loaded.
31523198
Object ccl = getAndSetContextClassLoader(MAILHANDLER_LOADER);
31533199
try {
3154-
final MimeMultipart multipart = new MimeMultipart();
3155-
final MimeBodyPart body = new MimeBodyPart();
3156-
body.setDisposition(Part.INLINE);
3200+
MimeMultipart multipart = new MimeMultipart();
3201+
MimeBodyPart[] ambp = new MimeBodyPart[atn.length];
3202+
final MimeBodyPart body;
3203+
final String bodyContentType;
3204+
synchronized (this) {
3205+
bodyContentType = contentTypeOf(getFormatter());
3206+
body = createBodyPart();
3207+
for (int i = 0; i < atn.length; ++i) {
3208+
ambp[i] = createBodyPart(i);
3209+
ambp[i].setFileName(atn[i]);
3210+
//Convert names to mime type.
3211+
atn[i] = getContentType(atn[i]);
3212+
}
3213+
}
3214+
31573215
body.setDescription(verify);
3158-
setAcceptLang(body);
3159-
setContent(body, "", "text/plain");
3216+
setContent(body, "", bodyContentType);
31603217
multipart.addBodyPart(body);
3218+
for (int i = 0; i < ambp.length; ++i) {
3219+
ambp[i].setDescription(verify);
3220+
setContent(ambp[i], "", atn[i]);
3221+
}
3222+
31613223
abort.setContent(multipart);
31623224
abort.saveChanges();
31633225
abort.writeTo(new ByteArrayOutputStream(MIN_HEADER_SIZE));
@@ -3220,6 +3282,8 @@ private void verifySettings0(Session session, String verify) {
32203282
* @param host the host or null.
32213283
* @return the address.
32223284
* @throws IOException if the host name is not valid.
3285+
* @throws SecurityException if security manager is present and doesn't
3286+
* allow access to check connect permission.
32233287
* @since JavaMail 1.5.0
32243288
*/
32253289
private static InetAddress verifyHost(String host) throws IOException {

mail/src/test/java/com/sun/mail/util/logging/MailHandlerTest.java

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,6 +2481,53 @@ public void testContentTypeOf() throws IOException {
24812481
}
24822482
}
24832483

2484+
@Test
2485+
public void testContentTypeOfFormatter() {
2486+
MailHandler instance = new MailHandler(createInitProperties(""));
2487+
InternalErrorManager em = new InternalErrorManager();
2488+
instance.setErrorManager(em);
2489+
2490+
assertEquals("text/plain", instance.contentTypeOf(new SimpleFormatter()));
2491+
assertEquals("text/plain", instance.contentTypeOf(new SimpleFormatter(){}));
2492+
2493+
assertEquals("application/xml", instance.contentTypeOf(new XMLFormatter()));
2494+
assertEquals("application/xml", instance.contentTypeOf(new XMLFormatter(){}));
2495+
2496+
/**
2497+
* None of the Formatter methods that can generate content should be
2498+
* invoked during a verify as that could lead to poor startup times.
2499+
*/
2500+
class UnsupportedHTML extends Formatter {
2501+
2502+
@Override
2503+
public String getHead(Handler h) {
2504+
throw new UnsupportedOperationException();
2505+
}
2506+
2507+
@Override
2508+
public String format(LogRecord record) {
2509+
throw new UnsupportedOperationException();
2510+
}
2511+
2512+
@Override
2513+
public String getTail(Handler h) {
2514+
throw new UnsupportedOperationException();
2515+
}
2516+
2517+
@Override
2518+
public String toString() {
2519+
throw new UnsupportedOperationException();
2520+
}
2521+
}
2522+
assertEquals("text/html", instance.contentTypeOf(new UnsupportedHTML()));
2523+
assertEquals("text/html", instance.contentTypeOf(new UnsupportedHTML(){}));
2524+
2525+
instance.close();
2526+
for (Exception exception : em.exceptions) {
2527+
fail(exception.toString());
2528+
}
2529+
}
2530+
24842531
@Test
24852532
public void testGuessContentTypeReadlimit() throws Exception {
24862533
class LastMarkInputStream extends ByteArrayInputStream {
@@ -5627,7 +5674,7 @@ public void testVerifyPropertiesConstructor() throws Exception {
56275674
Properties props = createInitProperties(p);
56285675
props.put(p.concat(".subject"), p.concat(" test"));
56295676
props.put(p.concat(".errorManager"), InternalErrorManager.class.getName());
5630-
5677+
props.put(p.concat(".formatter"), XMLFormatter.class.getName());
56315678
read(manager, props);
56325679

56335680
props = createInitProperties("");
@@ -5656,7 +5703,7 @@ public void testVerifyPropertiesConstructor() throws Exception {
56565703
props.put("subject", "test");
56575704
props.put("mail.from", "badAddress");
56585705
props.put("verify", "local");
5659-
5706+
56605707
instance = new MailHandler(props);
56615708
try {
56625709
InternalErrorManager em = internalErrorManagerFrom(instance);

0 commit comments

Comments
 (0)