De-couple ServiceLoader calls from class loading

Use the holder pattern to de-couple the loading of super classes from
the ServiceLoader calls to set up global instances. This prevents
potential lock inversions.

Bug: 579550
Change-Id: Ie8284e4d6d680ddd4cc6a486bbefe8ed00266240
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
Thomas Wolf 2022-04-03 21:06:57 +02:00
parent 7e06e51750
commit 7f9cd7d2ba
2 changed files with 65 additions and 28 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021, Thomas Wolf <thomas.wolf@paranor.ch> and others * Copyright (C) 2021, 2022 Thomas Wolf <thomas.wolf@paranor.ch> and others
* *
* This program and the accompanying materials are made available under the * This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at * terms of the Eclipse Distribution License v. 1.0 which is available at
@ -26,20 +26,41 @@ public abstract class GpgSignatureVerifierFactory {
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory
.getLogger(GpgSignatureVerifierFactory.class); .getLogger(GpgSignatureVerifierFactory.class);
private static volatile GpgSignatureVerifierFactory defaultFactory = loadDefault(); private static class DefaultFactory {
private static GpgSignatureVerifierFactory loadDefault() { private static volatile GpgSignatureVerifierFactory defaultFactory = loadDefault();
try {
ServiceLoader<GpgSignatureVerifierFactory> loader = ServiceLoader private static GpgSignatureVerifierFactory loadDefault() {
.load(GpgSignatureVerifierFactory.class); try {
Iterator<GpgSignatureVerifierFactory> iter = loader.iterator(); ServiceLoader<GpgSignatureVerifierFactory> loader = ServiceLoader
if (iter.hasNext()) { .load(GpgSignatureVerifierFactory.class);
return iter.next(); Iterator<GpgSignatureVerifierFactory> iter = loader.iterator();
if (iter.hasNext()) {
return iter.next();
}
} catch (ServiceConfigurationError e) {
LOG.error(e.getMessage(), e);
} }
} catch (ServiceConfigurationError e) { return null;
LOG.error(e.getMessage(), e); }
private DefaultFactory() {
// No instantiation
}
public static GpgSignatureVerifierFactory getDefault() {
return defaultFactory;
}
/**
* Sets the default factory.
*
* @param factory
* the new default factory
*/
public static void setDefault(GpgSignatureVerifierFactory factory) {
defaultFactory = factory;
} }
return null;
} }
/** /**
@ -48,7 +69,7 @@ private static GpgSignatureVerifierFactory loadDefault() {
* @return the default factory or {@code null} if none set * @return the default factory or {@code null} if none set
*/ */
public static GpgSignatureVerifierFactory getDefault() { public static GpgSignatureVerifierFactory getDefault() {
return defaultFactory; return DefaultFactory.getDefault();
} }
/** /**
@ -58,7 +79,7 @@ public static GpgSignatureVerifierFactory getDefault() {
* the new default factory * the new default factory
*/ */
public static void setDefault(GpgSignatureVerifierFactory factory) { public static void setDefault(GpgSignatureVerifierFactory factory) {
defaultFactory = factory; DefaultFactory.setDefault(factory);
} }
/** /**

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, 2020 Shawn O. Pearce <spearce@spearce.org> and others * Copyright (C) 2008, 2022 Shawn O. Pearce <spearce@spearce.org> and others
* *
* This program and the accompanying materials are made available under the * This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at * terms of the Eclipse Distribution License v. 1.0 which is available at
@ -36,15 +36,35 @@
*/ */
public abstract class SshSessionFactory { public abstract class SshSessionFactory {
private static volatile SshSessionFactory INSTANCE = loadSshSessionFactory(); private static class DefaultFactory {
private static SshSessionFactory loadSshSessionFactory() { private static volatile SshSessionFactory INSTANCE = loadSshSessionFactory();
ServiceLoader<SshSessionFactory> loader = ServiceLoader.load(SshSessionFactory.class);
Iterator<SshSessionFactory> iter = loader.iterator(); private static SshSessionFactory loadSshSessionFactory() {
if(iter.hasNext()) { ServiceLoader<SshSessionFactory> loader = ServiceLoader
return iter.next(); .load(SshSessionFactory.class);
Iterator<SshSessionFactory> iter = loader.iterator();
if (iter.hasNext()) {
return iter.next();
}
return null;
}
private DefaultFactory() {
// No instantiation
}
public static SshSessionFactory getInstance() {
return INSTANCE;
}
public static void setInstance(SshSessionFactory newFactory) {
if (newFactory != null) {
INSTANCE = newFactory;
} else {
INSTANCE = loadSshSessionFactory();
}
} }
return null;
} }
/** /**
@ -57,7 +77,7 @@ private static SshSessionFactory loadSshSessionFactory() {
* @return factory the current factory for this JVM. * @return factory the current factory for this JVM.
*/ */
public static SshSessionFactory getInstance() { public static SshSessionFactory getInstance() {
return INSTANCE; return DefaultFactory.getInstance();
} }
/** /**
@ -68,11 +88,7 @@ public static SshSessionFactory getInstance() {
* {@code null} the default factory will be restored. * {@code null} the default factory will be restored.
*/ */
public static void setInstance(SshSessionFactory newFactory) { public static void setInstance(SshSessionFactory newFactory) {
if (newFactory != null) { DefaultFactory.setInstance(newFactory);
INSTANCE = newFactory;
} else {
INSTANCE = loadSshSessionFactory();
}
} }
/** /**