Skip to content

Commit dbb0aa1

Browse files
authored
Jakarta Mail erroneously assumes that classes can be loaded from Thread#getContextClassLoader (#701)
* Jakarta Mail erroneously assumes that classes can be loaded from Thread#getContextClassLoader Signed-off-by: jmehrens <[email protected]>
1 parent 6c9ac50 commit dbb0aa1

File tree

5 files changed

+216
-92
lines changed

5 files changed

+216
-92
lines changed

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

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.security.PrivilegedActionException;
3737
import java.security.PrivilegedExceptionAction;
3838
import java.util.ArrayList;
39+
import java.util.Arrays;
3940
import java.util.Collections;
4041
import java.util.HashMap;
4142
import java.util.Hashtable;
@@ -255,7 +256,7 @@ private Session(Properties props, Authenticator authenticator) {
255256
this.authenticator = authenticator;
256257
this.streamProvider = StreamProvider.provider();
257258

258-
if (Boolean.valueOf(props.getProperty("mail.debug")).booleanValue())
259+
if (Boolean.parseBoolean(props.getProperty("mail.debug")))
259260
debug = true;
260261

261262
initLogger();
@@ -982,21 +983,28 @@ public void load(InputStream is) throws IOException {
982983
} catch (SecurityException ex) {
983984
}
984985

986+
//Fetch classloader of given class, falling back to others if needed.
987+
ClassLoader gcl;
988+
ClassLoader[] loaders = getClassLoaders(cl, Thread.class, System.class);
989+
if (loaders.length != 0) {
990+
gcl = loaders[0];
991+
} else {
992+
gcl = getContextClassLoader(); //Fail safe
993+
}
994+
985995
// next, add all the non-default services
986-
ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class);
996+
ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class, gcl);
987997
for (Provider p : sl) {
988998
if (!containsDefaultProvider(p))
989999
addProvider(p);
9901000
}
9911001

9921002
// + handle Glassfish/OSGi (platform specific default)
993-
if (isHk2Available()) {
994-
Iterator<Provider> iter = lookupUsingHk2ServiceLoader(Provider.class.getName());
995-
while (iter.hasNext()) {
996-
Provider p = iter.next();
997-
if (!containsDefaultProvider(p))
998-
addProvider(p);
999-
}
1003+
Iterator<Provider> iter = lookupUsingHk2ServiceLoader(Provider.class, gcl);
1004+
while (iter.hasNext()) {
1005+
Provider p = iter.next();
1006+
if (!containsDefaultProvider(p))
1007+
addProvider(p);
10001008
}
10011009

10021010
// load the META-INF/javamail.providers file supplied by an application
@@ -1006,46 +1014,44 @@ public void load(InputStream is) throws IOException {
10061014
loadResource("/META-INF/javamail.default.providers", cl, loader, false);
10071015

10081016
// finally, add all the default services
1009-
sl = ServiceLoader.load(Provider.class);
1017+
sl = ServiceLoader.load(Provider.class, gcl);
10101018
for (Provider p : sl) {
10111019
if (containsDefaultProvider(p))
10121020
addProvider(p);
10131021
}
10141022

10151023
// + handle Glassfish/OSGi (platform specific default)
1016-
if (isHk2Available()) {
1017-
Iterator<Provider> iter = lookupUsingHk2ServiceLoader(Provider.class.getName());
1018-
while (iter.hasNext()) {
1019-
Provider p = iter.next();
1020-
if (containsDefaultProvider(p)) {
1021-
addProvider(p);
1022-
}
1024+
iter = lookupUsingHk2ServiceLoader(Provider.class, gcl);
1025+
while (iter.hasNext()) {
1026+
Provider p = iter.next();
1027+
if (containsDefaultProvider(p)) {
1028+
addProvider(p);
10231029
}
10241030
}
10251031

10261032
/*
10271033
* If we haven't loaded any providers, fake it.
10281034
*/
1029-
if (providers.size() == 0) {
1035+
if (providers.isEmpty()) {
10301036
logger.config("failed to load any providers, using defaults");
10311037
// failed to load any providers, initialize with our defaults
10321038
addProvider(new Provider(Provider.Type.STORE,
1033-
"imap", "com.sun.mail.imap.IMAPStore",
1039+
"imap", "org.eclipse.angus.mail.imap.IMAPStore",
10341040
"Oracle", Version.version));
10351041
addProvider(new Provider(Provider.Type.STORE,
1036-
"imaps", "com.sun.mail.imap.IMAPSSLStore",
1042+
"imaps", "org.eclipse.angus.mail.imap.IMAPSSLStore",
10371043
"Oracle", Version.version));
10381044
addProvider(new Provider(Provider.Type.STORE,
1039-
"pop3", "com.sun.mail.pop3.POP3Store",
1045+
"pop3", "org.eclipse.angus.mail.pop3.POP3Store",
10401046
"Oracle", Version.version));
10411047
addProvider(new Provider(Provider.Type.STORE,
1042-
"pop3s", "com.sun.mail.pop3.POP3SSLStore",
1048+
"pop3s", "org.eclipse.angus.mail.pop3.POP3SSLStore",
10431049
"Oracle", Version.version));
10441050
addProvider(new Provider(Provider.Type.TRANSPORT,
1045-
"smtp", "com.sun.mail.smtp.SMTPTransport",
1051+
"smtp", "org.eclipse.angus.mail.smtp.SMTPTransport",
10461052
"Oracle", Version.version));
10471053
addProvider(new Provider(Provider.Type.TRANSPORT,
1048-
"smtps", "com.sun.mail.smtp.SMTPSSLTransport",
1054+
"smtps", "org.eclipse.angus.mail.smtp.SMTPSSLTransport",
10491055
"Oracle", Version.version));
10501056
}
10511057

@@ -1307,6 +1313,46 @@ public ClassLoader run() {
13071313
);
13081314
}
13091315

1316+
private static ClassLoader[] getClassLoaders(final Class<?>... classes) {
1317+
return AccessController.doPrivileged(
1318+
new PrivilegedAction<ClassLoader[]>() {
1319+
@Override
1320+
public ClassLoader[] run() {
1321+
ClassLoader[] loaders = new ClassLoader[classes.length];
1322+
int w = 0;
1323+
for (Class<?> k : classes) {
1324+
ClassLoader cl = null;
1325+
if (k == Thread.class) {
1326+
try {
1327+
cl = Thread.currentThread().getContextClassLoader();
1328+
} catch (SecurityException ex) {
1329+
}
1330+
} else if (k == System.class) {
1331+
try {
1332+
cl = ClassLoader.getSystemClassLoader();
1333+
} catch (SecurityException ex) {
1334+
}
1335+
} else {
1336+
try {
1337+
cl = k.getClassLoader();
1338+
} catch (SecurityException ex) {
1339+
}
1340+
}
1341+
1342+
if (cl != null) {
1343+
loaders[w++] = cl;
1344+
}
1345+
}
1346+
1347+
if (loaders.length != w) {
1348+
loaders = Arrays.copyOf(loaders, w);
1349+
}
1350+
return loaders;
1351+
}
1352+
}
1353+
);
1354+
}
1355+
13101356
private static InputStream getResourceAsStream(final Class<?> c, final String name) throws IOException {
13111357
try {
13121358
return AccessController.doPrivileged(
@@ -1386,33 +1432,44 @@ EventQueue getEventQueue() {
13861432
return q;
13871433
}
13881434

1389-
private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "org.glassfish.hk2.osgiresourcelocator.ServiceLoader";
1435+
private static Class<?>[] getHk2ServiceLoaderTargets(Class<?> factoryClass) {
1436+
ClassLoader[] loaders = getClassLoaders(Thread.class, factoryClass, System.class);
13901437

1391-
private static boolean isHk2Available() {
1392-
try {
1393-
Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME);
1394-
return true;
1395-
} catch (ClassNotFoundException ignored) {
1438+
Class<?>[] classes = new Class<?>[loaders.length];
1439+
int w = 0;
1440+
for (ClassLoader loader : loaders) {
1441+
if (loader != null) {
1442+
try {
1443+
classes[w++] = Class.forName("org.glassfish.hk2.osgiresourcelocator.ServiceLoader", false, loader);
1444+
} catch (Exception | LinkageError ignored) {
1445+
} //GlassFish class loaders can throw undocumented exceptions
1446+
}
13961447
}
1397-
return false;
1448+
1449+
if (classes.length != w) {
1450+
classes = Arrays.copyOf(classes, w);
1451+
}
1452+
return classes;
13981453
}
13991454

14001455
@SuppressWarnings({"unchecked"})
1401-
private <T> Iterator<T> lookupUsingHk2ServiceLoader(String factoryId) {
1402-
try {
1403-
// Use reflection to avoid having any dependency on HK2 ServiceLoader class
1404-
Class<?> serviceClass = Class.forName(factoryId);
1405-
Class<?>[] args = new Class<?>[]{serviceClass};
1406-
Class<?> target = Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME);
1407-
Method m = target.getMethod("lookupProviderInstances", Class.class);
1408-
Iterable<T> result = ((Iterable<T>) m.invoke(null, (Object[]) args));
1409-
return result != null ? result.iterator() : Collections.emptyIterator();
1410-
} catch (Exception ignored) {
1411-
// log and continue
1412-
return Collections.emptyIterator();
1456+
private <T> Iterator<T> lookupUsingHk2ServiceLoader(Class<T> factoryId, ClassLoader loader) {
1457+
for (Class<?> target : getHk2ServiceLoaderTargets(factoryId)) {
1458+
try {
1459+
// Use reflection to avoid having any dependency on HK2 ServiceLoader class
1460+
Class<?> serviceClass = Class.forName(factoryId.getName(), false, loader);
1461+
Class<?>[] args = new Class<?>[]{serviceClass};
1462+
Method m = target.getMethod("lookupProviderInstances", Class.class);
1463+
Iterable<T> result = ((Iterable<T>) m.invoke(null, (Object[]) args));
1464+
if (result != null) {
1465+
return result.iterator();
1466+
}
1467+
} catch (Exception ignored) {
1468+
// log and continue
1469+
}
14131470
}
1471+
return Collections.emptyIterator();
14141472
}
1415-
14161473
}
14171474

14181475
/**

0 commit comments

Comments
 (0)