mirror of https://github.com/apache/lucene.git
Fix classloading deadlock in analysis factories / AnalysisSPILoader initialization. This closes #11701 (#11718)
This commit is contained in:
parent
53b1ce7504
commit
1d54299011
|
@ -124,6 +124,9 @@ Bug Fixes
|
||||||
|
|
||||||
* LUCENE-10644: Facets#getAllChildren testing should ignore child order. (Yuting Gan)
|
* LUCENE-10644: Facets#getAllChildren testing should ignore child order. (Yuting Gan)
|
||||||
|
|
||||||
|
* LUCENE-10665, GITHUB#11701: Fix classloading deadlock in analysis factories / AnalysisSPILoader
|
||||||
|
initialization. (Uwe Schindler)
|
||||||
|
|
||||||
Build
|
Build
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|
|
@ -27,22 +27,39 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public abstract class CharFilterFactory extends AbstractAnalysisFactory {
|
public abstract class CharFilterFactory extends AbstractAnalysisFactory {
|
||||||
|
|
||||||
private static final AnalysisSPILoader<CharFilterFactory> loader =
|
/**
|
||||||
|
* This static holder class prevents classloading deadlock by delaying init of factories until
|
||||||
|
* needed.
|
||||||
|
*/
|
||||||
|
private static final class Holder {
|
||||||
|
private static final AnalysisSPILoader<CharFilterFactory> LOADER =
|
||||||
new AnalysisSPILoader<>(CharFilterFactory.class);
|
new AnalysisSPILoader<>(CharFilterFactory.class);
|
||||||
|
|
||||||
|
private Holder() {}
|
||||||
|
|
||||||
|
static AnalysisSPILoader<CharFilterFactory> getLoader() {
|
||||||
|
if (LOADER == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"You tried to lookup a CharFilterFactory by name before all factories could be initialized. "
|
||||||
|
+ "This likely happens if you call CharFilterFactory#forName from a CharFilterFactory's ctor.");
|
||||||
|
}
|
||||||
|
return LOADER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** looks up a charfilter by name from context classpath */
|
/** looks up a charfilter by name from context classpath */
|
||||||
public static CharFilterFactory forName(String name, Map<String, String> args) {
|
public static CharFilterFactory forName(String name, Map<String, String> args) {
|
||||||
return loader.newInstance(name, args);
|
return Holder.getLoader().newInstance(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** looks up a charfilter class by name from context classpath */
|
/** looks up a charfilter class by name from context classpath */
|
||||||
public static Class<? extends CharFilterFactory> lookupClass(String name) {
|
public static Class<? extends CharFilterFactory> lookupClass(String name) {
|
||||||
return loader.lookupClass(name);
|
return Holder.getLoader().lookupClass(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** returns a list of all available charfilter names */
|
/** returns a list of all available charfilter names */
|
||||||
public static Set<String> availableCharFilters() {
|
public static Set<String> availableCharFilters() {
|
||||||
return loader.availableServices();
|
return Holder.getLoader().availableServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** looks up a SPI name for the specified char filter factory */
|
/** looks up a SPI name for the specified char filter factory */
|
||||||
|
@ -65,7 +82,7 @@ public abstract class CharFilterFactory extends AbstractAnalysisFactory {
|
||||||
* given classpath/classloader!</em>
|
* given classpath/classloader!</em>
|
||||||
*/
|
*/
|
||||||
public static void reloadCharFilters(ClassLoader classloader) {
|
public static void reloadCharFilters(ClassLoader classloader) {
|
||||||
loader.reload(classloader);
|
Holder.getLoader().reload(classloader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Default ctor for compatibility with SPI */
|
/** Default ctor for compatibility with SPI */
|
||||||
|
|
|
@ -27,22 +27,39 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public abstract class TokenFilterFactory extends AbstractAnalysisFactory {
|
public abstract class TokenFilterFactory extends AbstractAnalysisFactory {
|
||||||
|
|
||||||
private static final AnalysisSPILoader<TokenFilterFactory> loader =
|
/**
|
||||||
|
* This static holder class prevents classloading deadlock by delaying init of factories until
|
||||||
|
* needed.
|
||||||
|
*/
|
||||||
|
private static final class Holder {
|
||||||
|
private static final AnalysisSPILoader<TokenFilterFactory> LOADER =
|
||||||
new AnalysisSPILoader<>(TokenFilterFactory.class);
|
new AnalysisSPILoader<>(TokenFilterFactory.class);
|
||||||
|
|
||||||
|
private Holder() {}
|
||||||
|
|
||||||
|
static AnalysisSPILoader<TokenFilterFactory> getLoader() {
|
||||||
|
if (LOADER == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"You tried to lookup a TokenFilterFactory by name before all factories could be initialized. "
|
||||||
|
+ "This likely happens if you call TokenFilterFactory#forName from a TokenFilterFactory's ctor.");
|
||||||
|
}
|
||||||
|
return LOADER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** looks up a tokenfilter by name from context classpath */
|
/** looks up a tokenfilter by name from context classpath */
|
||||||
public static TokenFilterFactory forName(String name, Map<String, String> args) {
|
public static TokenFilterFactory forName(String name, Map<String, String> args) {
|
||||||
return loader.newInstance(name, args);
|
return Holder.getLoader().newInstance(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** looks up a tokenfilter class by name from context classpath */
|
/** looks up a tokenfilter class by name from context classpath */
|
||||||
public static Class<? extends TokenFilterFactory> lookupClass(String name) {
|
public static Class<? extends TokenFilterFactory> lookupClass(String name) {
|
||||||
return loader.lookupClass(name);
|
return Holder.getLoader().lookupClass(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** returns a list of all available tokenfilter names from context classpath */
|
/** returns a list of all available tokenfilter names from context classpath */
|
||||||
public static Set<String> availableTokenFilters() {
|
public static Set<String> availableTokenFilters() {
|
||||||
return loader.availableServices();
|
return Holder.getLoader().availableServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** looks up a SPI name for the specified token filter factory */
|
/** looks up a SPI name for the specified token filter factory */
|
||||||
|
@ -65,7 +82,7 @@ public abstract class TokenFilterFactory extends AbstractAnalysisFactory {
|
||||||
* given classpath/classloader!</em>
|
* given classpath/classloader!</em>
|
||||||
*/
|
*/
|
||||||
public static void reloadTokenFilters(ClassLoader classloader) {
|
public static void reloadTokenFilters(ClassLoader classloader) {
|
||||||
loader.reload(classloader);
|
Holder.getLoader().reload(classloader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Default ctor for compatibility with SPI */
|
/** Default ctor for compatibility with SPI */
|
||||||
|
|
|
@ -27,22 +27,39 @@ import org.apache.lucene.util.AttributeFactory;
|
||||||
*/
|
*/
|
||||||
public abstract class TokenizerFactory extends AbstractAnalysisFactory {
|
public abstract class TokenizerFactory extends AbstractAnalysisFactory {
|
||||||
|
|
||||||
private static final AnalysisSPILoader<TokenizerFactory> loader =
|
/**
|
||||||
|
* This static holder class prevents classloading deadlock by delaying init of factories until
|
||||||
|
* needed.
|
||||||
|
*/
|
||||||
|
private static final class Holder {
|
||||||
|
private static final AnalysisSPILoader<TokenizerFactory> LOADER =
|
||||||
new AnalysisSPILoader<>(TokenizerFactory.class);
|
new AnalysisSPILoader<>(TokenizerFactory.class);
|
||||||
|
|
||||||
|
private Holder() {}
|
||||||
|
|
||||||
|
static AnalysisSPILoader<TokenizerFactory> getLoader() {
|
||||||
|
if (LOADER == null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"You tried to lookup a TokenizerFactory by name before all factories could be initialized. "
|
||||||
|
+ "This likely happens if you call TokenizerFactory#forName from a TokenizerFactory ctor.");
|
||||||
|
}
|
||||||
|
return LOADER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** looks up a tokenizer by name from context classpath */
|
/** looks up a tokenizer by name from context classpath */
|
||||||
public static TokenizerFactory forName(String name, Map<String, String> args) {
|
public static TokenizerFactory forName(String name, Map<String, String> args) {
|
||||||
return loader.newInstance(name, args);
|
return Holder.getLoader().newInstance(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** looks up a tokenizer class by name from context classpath */
|
/** looks up a tokenizer class by name from context classpath */
|
||||||
public static Class<? extends TokenizerFactory> lookupClass(String name) {
|
public static Class<? extends TokenizerFactory> lookupClass(String name) {
|
||||||
return loader.lookupClass(name);
|
return Holder.getLoader().lookupClass(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** returns a list of all available tokenizer names from context classpath */
|
/** returns a list of all available tokenizer names from context classpath */
|
||||||
public static Set<String> availableTokenizers() {
|
public static Set<String> availableTokenizers() {
|
||||||
return loader.availableServices();
|
return Holder.getLoader().availableServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** looks up a SPI name for the specified tokenizer factory */
|
/** looks up a SPI name for the specified tokenizer factory */
|
||||||
|
@ -65,7 +82,7 @@ public abstract class TokenizerFactory extends AbstractAnalysisFactory {
|
||||||
* given classpath/classloader!</em>
|
* given classpath/classloader!</em>
|
||||||
*/
|
*/
|
||||||
public static void reloadTokenizers(ClassLoader classloader) {
|
public static void reloadTokenizers(ClassLoader classloader) {
|
||||||
loader.reload(classloader);
|
Holder.getLoader().reload(classloader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Default ctor for compatibility with SPI */
|
/** Default ctor for compatibility with SPI */
|
||||||
|
|
Loading…
Reference in New Issue