Skip to content

Commit cf42970

Browse files
committed
Custom mail providers distributed under META-INF/javamail.properties are no longer loaded with Jakarta Mail 2.1.5 #812
Signed-off-by: Jorge Bescos Gascon <[email protected]>
1 parent 82f1e48 commit cf42970

File tree

11 files changed

+207
-92
lines changed

11 files changed

+207
-92
lines changed

api/src/main/java/jakarta/mail/Provider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
* configuring providers using the Java SE
2323
* {@link java.util.ServiceLoader ServiceLoader} mechanism.
2424
* As an alternative the values could come from the
25-
* javamail.providers and javamail.default.providers
25+
* javamail.providers, javamail.default.providers,
26+
* jakarta.providers and jakarta.default.providers
2627
* resource files. An application may also create and
2728
* register a Provider object to dynamically add support
2829
* for a new provider.

api/src/main/java/jakarta/mail/Session.java

Lines changed: 67 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,22 @@
5555
* implement the <code>Store</code>, <code>Transport</code>, and related
5656
* classes. The protocol providers are configured using the following files:
5757
* <ul>
58-
* <li> <code>jakarta.providers</code> and
59-
* <code>jakarta.default.providers</code> </li>
60-
* <li> <code>jakarta.address.map</code> and
58+
* <li> <code>javamail.providers</code>,
59+
* <code>javamail.default.providers</code>,
60+
* <code>jakarta.providers</code> and
61+
* <code>jakarta.default.providers</code></li>
62+
* <li><code>javamail.address.map</code>,
63+
* <code>javamail.default.address.map</code>,
64+
* <code>jakarta.address.map</code> and
6165
* <code>jakarta.default.address.map</code> </li>
6266
* </ul>
6367
* <p>
64-
* Each <code>jakarta.</code><i>X</i> resource file is searched for using
65-
* three methods in the following order:
68+
* Each <code>javamail.</code><i>X</i> and <code>jakarta.</code><i>X</i>
69+
* resource file is searched for using three methods in the following order:
6670
* <ol>
71+
* <li> <code><i>java.home</i>/<i>conf</i>/javamail.</code><i>X</i> </li>
72+
* <li> <code>META-INF/javamail.</code><i>X</i> </li>
73+
* <li> <code>META-INF/javamail.default.</code><i>X</i> </li>
6774
* <li> <code><i>java.home</i>/<i>conf</i>/jakarta.</code><i>X</i> </li>
6875
* <li> <code>META-INF/jakarta.</code><i>X</i> </li>
6976
* <li> <code>META-INF/jakarta.default.</code><i>X</i> </li>
@@ -79,7 +86,8 @@
7986
* <code>java.home</code> property points. The second method allows an
8087
* application that uses the Jakarta Mail APIs to include their own resource
8188
* files in their application's or jar file's <code>META-INF</code>
82-
* directory. The <code>jakarta.default.</code><i>X</i> default files
89+
* directory. The <code>javamail.default.</code><i>X</i> and
90+
* <code>jakarta.default.</code><i>X</i> default files
8391
* are part of the Jakarta Mail <code>mail.jar</code> file and should not be
8492
* supplied by users. <p>
8593
*
@@ -96,6 +104,8 @@
96104
* do not override, the default files included with the Jakarta Mail APIs.
97105
* This means that all entries in all files loaded will be available. <p>
98106
*
107+
* <b><code>javamail.providers</code></b>,
108+
* <b><code>javamail.default.providers</code></b>,
99109
* <b><code>jakarta.providers</code></b> and
100110
* <b><code>jakarta.default.providers</code></b><p>
101111
*
@@ -168,13 +178,16 @@
168178
* </pre>
169179
* <p>
170180
*
181+
* <b><code>javamail.address.map</code></b>,
182+
* <b><code>javamail.default.address.map</code></b>,
171183
* <b><code>jakarta.address.map</code></b> and
172184
* <b><code>jakarta.default.address.map</code></b><p>
173185
*
174186
* These resource files map transport address types to the transport
175187
* protocol. The <code>getType</code> method of
176188
* <code>jakarta.mail.Address</code> returns the address type. The
177-
* <code>jakarta.address.map</code> file maps the transport type to the
189+
* <code>javamail.address.map</code> and <code>jakarta.address.map</code>
190+
* files map the transport type to the
178191
* protocol. The file format is a series of name-value pairs. Each key
179192
* name should correspond to an address type that is currently installed
180193
* on the system; there should also be an entry for each
@@ -202,11 +215,12 @@ public final class Session {
202215
// Support legacy @DefaultProvider
203216
private static final String DEFAULT_PROVIDER = "org.eclipse.angus.mail.util.DefaultProvider";
204217

205-
// This is for backwards compatibility. Eventually we have to remove the second value of the next arrays.
206-
private static final String[] DEFAULT_ADDRESS_MAP_RESOURCES = new String[] {"/META-INF/jakarta.default.address.map", "/META-INF/javamail.default.address.map"};
207-
private static final String[] ADDRESS_MAP_RESOURCES = new String[] {"META-INF/jakarta.address.map", "META-INF/javamail.address.map"};
208-
private static final String[] DEFAULT_PROVIDER_RESOURCES = new String[] {"/META-INF/jakarta.default.providers", "/META-INF/javamail.default.providers"};
209-
private static final String[] PROVIDER_RESOURCES = new String[] {"META-INF/jakarta.providers", "META-INF/javamail.providers"};
218+
// This is for backwards compatibility. javamail has more precedence than jakarta to not break compatibility
219+
// Eventually we have to remove the first value of the next arrays.
220+
private static final String[] DEFAULT_ADDRESS_MAP_RESOURCES = new String[] {"/META-INF/javamail.default.address.map", "/META-INF/jakarta.default.address.map"};
221+
private static final String[] ADDRESS_MAP_RESOURCES = new String[] {"META-INF/javamail.address.map", "META-INF/jakarta.address.map"};
222+
private static final String[] DEFAULT_PROVIDER_RESOURCES = new String[] {"/META-INF/javamail.default.providers", "/META-INF/jakarta.default.providers"};
223+
private static final String[] PROVIDER_RESOURCES = new String[] {"META-INF/javamail.providers", "META-INF/jakarta.providers"};
210224

211225
private final StreamProvider streamProvider;
212226
private final Properties props;
@@ -467,8 +481,8 @@ public synchronized PrintStream getDebugOut() {
467481

468482
/**
469483
* This method returns an array of all the implementations installed
470-
* via the jakarta.[default.]providers files that can
471-
* be loaded using the ClassLoader available to this application.
484+
* via the javamail.[default.]providers and jakarta.[default.]providers
485+
* files that can be loaded using the ClassLoader available to this application.
472486
*
473487
* @return Array of configured providers
474488
*/
@@ -949,10 +963,10 @@ public void load(InputStream is) throws IOException {
949963
}
950964
};
951965

952-
// load system-wide jakarta.providers from the
966+
// load system-wide javamail.providers and jakarta.providers from the
953967
// <java.home>/{conf,lib} directory
954968
if (confDir != null)
955-
loadFile(loader, confDir + "jakarta.providers", confDir + "javamail.providers");
969+
loadFile(loader, confDir + "javamail.providers", confDir + "jakarta.providers");
956970

957971
//Fetch classloader of given class, falling back to others if needed.
958972
ClassLoader gcl;
@@ -978,10 +992,10 @@ public void load(InputStream is) throws IOException {
978992
addProvider(p);
979993
}
980994

981-
// load the META-INF/jakarta.providers file supplied by an application
995+
// load the META-INF/javamail.providers and META-INF/jakarta.providers file supplied by an application
982996
loadAllResources(cl, loader, PROVIDER_RESOURCES);
983997

984-
// load default META-INF/jakarta.default.providers from mail.jar file
998+
// load default META-INF/javamail.providers and META-INF/jakarta.default.providers from mail.jar file
985999
loadResource(cl, loader, false, DEFAULT_PROVIDER_RESOURCES);
9861000

9871001
// finally, add all the default services
@@ -1102,7 +1116,8 @@ private void loadProvidersFromStream(InputStream is) throws IOException {
11021116
*/
11031117
public synchronized void addProvider(Provider provider) {
11041118
providers.add(provider);
1105-
providersByClassName.put(provider.getClassName(), provider);
1119+
if (!providersByClassName.containsKey(provider.getClassName()))
1120+
providersByClassName.put(provider.getClassName(), provider);
11061121
if (!providersByProtocol.containsKey(provider.getProtocol()))
11071122
providersByProtocol.put(provider.getProtocol(), provider);
11081123
}
@@ -1117,16 +1132,16 @@ public void load(InputStream is) throws IOException {
11171132
}
11181133
};
11191134

1120-
// load default META-INF/jakarta.default.address.map from mail.jar
1135+
// load default META-INF/javamail.default.address.map and META-INF/jakarta.default.address.map from mail.jar
11211136
loadResource(cl, loader, true, DEFAULT_ADDRESS_MAP_RESOURCES);
11221137

1123-
// load the META-INF/jakarta.address.map file supplied by an app
1138+
// load the META-INF/javamail.address.map and META-INF/jakarta.address.map files supplied by an app
11241139
loadAllResources(cl, loader, ADDRESS_MAP_RESOURCES);
11251140

1126-
// load system-wide jakarta.address.map from the
1141+
// load system-wide javamail.address.map and jakarta.address.map from the
11271142
// <java.home>/{conf,lib} directory
11281143
if (confDir != null)
1129-
loadFile(loader, confDir + "jakarta.address.map", confDir + "javamail.address.map");
1144+
loadFile(loader, confDir + "javamail.address.map", confDir + "jakarta.address.map");
11301145

11311146
if (addressMap.isEmpty()) {
11321147
logger.config("failed to load address map, using defaults");
@@ -1156,24 +1171,20 @@ public synchronized void setProtocolForAddress(String addresstype, String protoc
11561171
* Load from the named file.
11571172
*/
11581173
private void loadFile(StreamLoader loader, String ... names) {
1159-
InputStream clis = null;
1160-
for (String name : names) {
1161-
try {
1162-
clis = new BufferedInputStream(new FileInputStream(name));
1174+
for (int i = 0; i < names.length; i++) {
1175+
String name = names[i];
1176+
try (InputStream clis = new BufferedInputStream(new FileInputStream(name))) {
11631177
loader.load(clis);
11641178
logger.log(Level.CONFIG, "successfully loaded file: {0}", name);
1165-
break;
1179+
// We already know size is two, but just in case, we don't want to fail here for a logger reason
1180+
if (i == 0 && names.length == 2) {
1181+
logger.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.", names[0], names[1]);
1182+
}
11661183
} catch (FileNotFoundException fex) {
11671184
// ignore it
11681185
} catch (IOException e) {
11691186
if (logger.isLoggable(Level.CONFIG))
11701187
logger.log(Level.CONFIG, "not loading file: " + name, e);
1171-
} finally {
1172-
try {
1173-
if (clis != null)
1174-
clis.close();
1175-
} catch (IOException ex) {
1176-
} // ignore it
11771188
}
11781189
}
11791190
}
@@ -1182,28 +1193,27 @@ private void loadFile(StreamLoader loader, String ... names) {
11821193
* Load from the named resource.
11831194
*/
11841195
private void loadResource(Class<?> cl, StreamLoader loader, boolean expected, String ... names) {
1185-
InputStream clis = null;
1186-
try {
1187-
for (String name : names) {
1188-
clis = getResourceAsStream(cl, name);
1196+
boolean loaded = false;
1197+
for (int i = 0; i < names.length; i++) {
1198+
String name = names[i];
1199+
try (InputStream clis = getResourceAsStream(cl, name)) {
11891200
if (clis != null) {
1201+
loaded = true;
11901202
loader.load(clis);
11911203
logger.log(Level.CONFIG, "successfully loaded resource: {0}", name);
1192-
break;
1204+
// We already know size is two, but just in case, we don't want to fail here for a logger reason
1205+
if (i == 0 && names.length == 2) {
1206+
logger.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.", names[0], names[1]);
1207+
}
11931208
}
1209+
} catch (IOException e) {
1210+
logger.log(Level.CONFIG, "Exception loading resource", e);
11941211
}
1195-
if (clis == null) {
1196-
if (expected)
1197-
logger.log(Level.WARNING, "expected resource not found: {0}", Arrays.asList(names));
1198-
}
1199-
} catch (IOException e) {
1200-
logger.log(Level.CONFIG, "Exception loading resource", e);
1201-
} finally {
1202-
try {
1203-
if (clis != null)
1204-
clis.close();
1205-
} catch (IOException ex) {
1206-
} // ignore it
1212+
1213+
}
1214+
if (!loaded) {
1215+
if (expected)
1216+
logger.log(Level.WARNING, "expected resource not found: {0}", Arrays.asList(names));
12071217
}
12081218
}
12091219

@@ -1213,7 +1223,8 @@ private void loadResource(Class<?> cl, StreamLoader loader, boolean expected, St
12131223
private void loadAllResources(Class<?> cl, StreamLoader loader, String ... names) {
12141224
boolean anyLoaded = false;
12151225
try {
1216-
for (String name : names) {
1226+
for (int j = 0; j < names.length; j++) {
1227+
String name = names[j];
12171228
URL[] urls;
12181229
ClassLoader cld = null;
12191230
// First try the "application's" class loader.
@@ -1227,10 +1238,8 @@ private void loadAllResources(Class<?> cl, StreamLoader loader, String ... names
12271238
if (urls != null) {
12281239
for (int i = 0; i < urls.length; i++) {
12291240
URL url = urls[i];
1230-
InputStream clis = null;
12311241
logger.log(Level.CONFIG, "URL {0}", url);
1232-
try {
1233-
clis = url.openStream();
1242+
try (InputStream clis = url.openStream()) {
12341243
if (clis != null) {
12351244
loader.load(clis);
12361245
anyLoaded = true;
@@ -1245,16 +1254,11 @@ private void loadAllResources(Class<?> cl, StreamLoader loader, String ... names
12451254
} catch (IOException ioex) {
12461255
logger.log(Level.CONFIG, "Exception loading resource",
12471256
ioex);
1248-
} finally {
1249-
try {
1250-
if (clis != null)
1251-
clis.close();
1252-
} catch (IOException cex) {
1253-
}
12541257
}
12551258
}
1256-
if (anyLoaded) {
1257-
break;
1259+
// We already know size is two, but just in case, we don't want to fail here for a logger reason
1260+
if (j == 0 && names.length == 2) {
1261+
logger.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.", names[0], names[1]);
12581262
}
12591263
}
12601264
}

api/src/main/java/jakarta/mail/internet/MimeUtility.java

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import java.util.NoSuchElementException;
4141
import java.util.Properties;
4242
import java.util.StringTokenizer;
43+
import java.util.logging.Level;
44+
import java.util.logging.Logger;
4345

4446
/**
4547
* This is a utility class that provides various MIME related
@@ -139,9 +141,12 @@ public class MimeUtility {
139141
private MimeUtility() {
140142
}
141143

144+
private static final Logger LOGGER = Logger.getLogger(MimeUtility.class.getName());
145+
142146
public static final int ALL = -1;
143147

144148
// This is for backwards compatibility. Eventually we have to remove the second value of the next array.
149+
// Note this order is different than in Session arrays. This is because here the key-value pair is overwritten.
145150
private static final String[] CHARSET_MAP_RESOURCES = new String[] {"/META-INF/jakarta.charset.map", "/META-INF/javamail.charset.map"};
146151

147152
// cached map of whether a charset is compatible with ASCII
@@ -1353,29 +1358,27 @@ static String getDefaultMIMECharset() {
13531358
java2mime = new HashMap<>(40);
13541359
mime2java = new HashMap<>(14);
13551360

1356-
try {
1357-
// Use this class's classloader to load the mapping file
1358-
// XXX - we should use SecuritySupport, but it's in another package
1359-
InputStream is = resource(CHARSET_MAP_RESOURCES);
1360-
1361-
if (is != null) {
1362-
try {
1361+
// Use this class's classloader to load the mapping file
1362+
// XXX - we should use SecuritySupport, but it's in another package
1363+
for (int i = 0; i < CHARSET_MAP_RESOURCES.length; i++) {
1364+
String charsetResource = CHARSET_MAP_RESOURCES[i];
1365+
try (InputStream is = MimeUtility.class.getResourceAsStream(charsetResource)) {
1366+
if (is != null) {
13631367
LineInputStream lineInput = StreamProvider.provider().inputLineStream(is, false);
13641368

13651369
// Load the JDK-to-MIME charset mapping table
13661370
loadMappings(lineInput, java2mime);
13671371

13681372
// Load the MIME-to-JDK charset mapping table
13691373
loadMappings(lineInput, mime2java);
1370-
} finally {
1371-
try {
1372-
is.close();
1373-
} catch (Exception cex) {
1374-
// ignore
1375-
}
13761374
}
1375+
// We already know size is two, but just in case, we don't want to fail here for a logger reason
1376+
if (i == 0 && CHARSET_MAP_RESOURCES.length == 2) {
1377+
LOGGER.log(Level.WARNING, "[DEPRECATED] {0} is deprecated and will be removed. Future versions will require {1}.",
1378+
new Object[]{CHARSET_MAP_RESOURCES[0], CHARSET_MAP_RESOURCES[1]});
1379+
}
1380+
} catch (Exception ex) {
13771381
}
1378-
} catch (Exception ex) {
13791382
}
13801383

13811384
// If we didn't load the tables, e.g., because we didn't have
@@ -1444,16 +1447,6 @@ static String getDefaultMIMECharset() {
14441447
mime2java.put("gbk", "GB18030");
14451448
}
14461449
}
1447-
1448-
private static InputStream resource(String[] resources) {
1449-
for (String resource : resources) {
1450-
InputStream is = MimeUtility.class.getResourceAsStream(resource);
1451-
if (is != null) {
1452-
return is;
1453-
}
1454-
}
1455-
return null;
1456-
}
14571450

14581451
private static void loadMappings(LineInputStream is,
14591452
Map<String, String> table) {

0 commit comments

Comments
 (0)