mirror of https://github.com/apache/lucene.git
LUCENE-2510: Make the SOLR backwards layer be implemented directly inside SolrResourceLoader (sorry for the generics and still needed suppress warnings... - maybe somebody has an idea for the map inside map)
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene2510@1365215 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b87e306e85
commit
d1ad745f53
|
@ -152,7 +152,6 @@ public class SynonymFilterFactory extends TokenFilterFactory implements Resource
|
|||
return parser.build();
|
||||
}
|
||||
|
||||
// nocommit: spi-hack solr.xxx and o.a.solr.analysis.xxx via a delegator
|
||||
// (there are no tests for this functionality)
|
||||
private TokenizerFactory loadTokenizerFactory(ResourceLoader loader, String cname){
|
||||
TokenizerFactory tokFactory = loader.newInstance(cname, TokenizerFactory.class);
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.apache.lucene.util.SPIClassIterator;
|
|||
* Helper class for loading named SPIs from classpath (e.g. Tokenizers, TokenStreams).
|
||||
* @lucene.internal
|
||||
*/
|
||||
final class AnalysisSPILoader<S extends AbstractAnalysisFactory> {
|
||||
public final class AnalysisSPILoader<S extends AbstractAnalysisFactory> {
|
||||
|
||||
private final Map<String,Class<? extends S>> services;
|
||||
private final Class<S> clazz;
|
||||
|
@ -37,9 +37,17 @@ final class AnalysisSPILoader<S extends AbstractAnalysisFactory> {
|
|||
this(clazz, new String[] { clazz.getSimpleName() });
|
||||
}
|
||||
|
||||
public AnalysisSPILoader(Class<S> clazz, ClassLoader loader) {
|
||||
this(clazz, new String[] { clazz.getSimpleName() }, loader);
|
||||
}
|
||||
|
||||
public AnalysisSPILoader(Class<S> clazz, String[] suffixes) {
|
||||
this(clazz, suffixes, Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
public AnalysisSPILoader(Class<S> clazz, String[] suffixes, ClassLoader classloader) {
|
||||
this.clazz = clazz;
|
||||
final SPIClassIterator<S> loader = SPIClassIterator.get(clazz);
|
||||
final SPIClassIterator<S> loader = SPIClassIterator.get(clazz, classloader);
|
||||
final LinkedHashMap<String,Class<? extends S>> services = new LinkedHashMap<String,Class<? extends S>>();
|
||||
while (loader.hasNext()) {
|
||||
final Class<? extends S> service = loader.next();
|
||||
|
|
|
@ -29,13 +29,23 @@ import org.apache.lucene.analysis.CharFilter;
|
|||
public abstract class CharFilterFactory extends AbstractAnalysisFactory {
|
||||
|
||||
private static final AnalysisSPILoader<CharFilterFactory> loader =
|
||||
new AnalysisSPILoader<CharFilterFactory>(CharFilterFactory.class);
|
||||
getSPILoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
/** looks up a charfilter by name */
|
||||
/**
|
||||
* Used by e.g. Apache Solr to get a correctly configured instance
|
||||
* of {@link AnalysisSPILoader} from Solr's classpath.
|
||||
* @lucene.internal
|
||||
*/
|
||||
public static AnalysisSPILoader<CharFilterFactory> getSPILoader(ClassLoader classloader) {
|
||||
return new AnalysisSPILoader<CharFilterFactory>(CharFilterFactory.class, classloader);
|
||||
}
|
||||
|
||||
/** looks up a charfilter by name from context classpath */
|
||||
public static CharFilterFactory forName(String name) {
|
||||
return loader.newInstance(name);
|
||||
}
|
||||
|
||||
/** looks up a charfilter class by name from context classpath */
|
||||
public static Class<? extends CharFilterFactory> lookupClass(String name) {
|
||||
return loader.lookupClass(name);
|
||||
}
|
||||
|
|
|
@ -28,19 +28,29 @@ import org.apache.lucene.analysis.TokenStream;
|
|||
public abstract class TokenFilterFactory extends AbstractAnalysisFactory {
|
||||
|
||||
private static final AnalysisSPILoader<TokenFilterFactory> loader =
|
||||
new AnalysisSPILoader<TokenFilterFactory>(TokenFilterFactory.class,
|
||||
new String[] { "TokenFilterFactory", "FilterFactory" });
|
||||
getSPILoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
/** looks up a tokenfilter by name */
|
||||
/**
|
||||
* Used by e.g. Apache Solr to get a correctly configured instance
|
||||
* of {@link AnalysisSPILoader} from Solr's classpath.
|
||||
* @lucene.internal
|
||||
*/
|
||||
public static AnalysisSPILoader<TokenFilterFactory> getSPILoader(ClassLoader classloader) {
|
||||
return new AnalysisSPILoader<TokenFilterFactory>(TokenFilterFactory.class,
|
||||
new String[] { "TokenFilterFactory", "FilterFactory" }, classloader);
|
||||
}
|
||||
|
||||
/** looks up a tokenfilter by name from context classpath */
|
||||
public static TokenFilterFactory forName(String name) {
|
||||
return loader.newInstance(name);
|
||||
}
|
||||
|
||||
/** looks up a tokenfilter class by name from context classpath */
|
||||
public static Class<? extends TokenFilterFactory> lookupClass(String name) {
|
||||
return loader.lookupClass(name);
|
||||
}
|
||||
|
||||
/** returns a list of all available tokenfilter names */
|
||||
/** returns a list of all available tokenfilter names from context classpath */
|
||||
public static Set<String> availableTokenFilters() {
|
||||
return loader.availableServices();
|
||||
}
|
||||
|
|
|
@ -29,18 +29,28 @@ import java.util.Set;
|
|||
public abstract class TokenizerFactory extends AbstractAnalysisFactory {
|
||||
|
||||
private static final AnalysisSPILoader<TokenizerFactory> loader =
|
||||
new AnalysisSPILoader<TokenizerFactory>(TokenizerFactory.class);
|
||||
getSPILoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
/** looks up a tokenizer by name */
|
||||
/**
|
||||
* Used by e.g. Apache Solr to get a correctly configured instance
|
||||
* of {@link AnalysisSPILoader} from Solr's classpath.
|
||||
* @lucene.internal
|
||||
*/
|
||||
public static AnalysisSPILoader<TokenizerFactory> getSPILoader(ClassLoader classloader) {
|
||||
return new AnalysisSPILoader<TokenizerFactory>(TokenizerFactory.class, classloader);
|
||||
}
|
||||
|
||||
/** looks up a tokenizer by name from context classpath */
|
||||
public static TokenizerFactory forName(String name) {
|
||||
return loader.newInstance(name);
|
||||
}
|
||||
|
||||
/** looks up a tokenizer class by name from context classpath */
|
||||
public static Class<? extends TokenizerFactory> lookupClass(String name) {
|
||||
return loader.lookupClass(name);
|
||||
}
|
||||
|
||||
/** returns a list of all available tokenizer names */
|
||||
/** returns a list of all available tokenizer names from context classpath */
|
||||
public static Set<String> availableTokenizers() {
|
||||
return loader.availableServices();
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package org.apache.solr.analysis;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.lucene.analysis.util.AbstractAnalysisFactory;
|
||||
import org.apache.lucene.analysis.util.ResourceLoader;
|
||||
import org.apache.solr.util.plugin.AbstractPluginLoader;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
public abstract class AnalysisPluginLoader<S extends AbstractAnalysisFactory> extends AbstractPluginLoader<S> {
|
||||
|
||||
public AnalysisPluginLoader(String type, Class<S> pluginClassType, boolean preRegister, boolean requireName) {
|
||||
super(type, pluginClassType, preRegister, requireName);
|
||||
}
|
||||
|
||||
public AnalysisPluginLoader(String type, Class<S> pluginClassType) {
|
||||
super(type, pluginClassType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected S create(ResourceLoader loader, String name, String className, Node node) throws Exception {
|
||||
Class<? extends S> clazz = null;
|
||||
Matcher m = legacyPattern.matcher(className);
|
||||
if (m.matches()) {
|
||||
try {
|
||||
clazz = lookupSPI(m.group(4));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// ok
|
||||
}
|
||||
}
|
||||
|
||||
if (clazz != null) {
|
||||
className = clazz.getName();
|
||||
}
|
||||
|
||||
return super.create(loader, name, className, node);
|
||||
}
|
||||
|
||||
private static final Pattern legacyPattern =
|
||||
Pattern.compile("((org\\.apache\\.solr\\.analysis\\.)|(solr\\.))([\\p{L}_$][\\p{L}\\p{N}_$]+?)(TokenFilter|Filter|Tokenizer|CharFilter)Factory");
|
||||
|
||||
protected abstract Class<? extends S> lookupSPI(String name);
|
||||
}
|
|
@ -29,11 +29,16 @@ import java.net.URL;
|
|||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.lucene.analysis.util.AbstractAnalysisFactory;
|
||||
import org.apache.lucene.analysis.util.CharFilterFactory;
|
||||
import org.apache.lucene.analysis.util.ResourceLoaderAware;
|
||||
import org.apache.lucene.analysis.util.TokenFilterFactory;
|
||||
import org.apache.lucene.analysis.util.TokenizerFactory;
|
||||
import org.apache.lucene.analysis.util.AnalysisSPILoader;
|
||||
import org.apache.lucene.util.WeakIdentityMap;
|
||||
import org.apache.solr.common.ResourceLoader;
|
||||
import org.apache.solr.handler.admin.CoreAdminHandler;
|
||||
import org.apache.solr.handler.component.ShardHandlerFactory;
|
||||
|
@ -366,8 +371,15 @@ public class SolrResourceLoader implements ResourceLoader
|
|||
/*
|
||||
* A static map of short class name to fully qualified class name
|
||||
*/
|
||||
private static Map<String, String> classNameCache = new ConcurrentHashMap<String, String>();
|
||||
private static final Map<String, String> classNameCache = new ConcurrentHashMap<String, String>();
|
||||
|
||||
// A static map of AnalysisSPILoaders, keyed by ClassLoader used (because it can change during Solr lifetime) and expected base class:
|
||||
private static final WeakIdentityMap<ClassLoader, Map<Class<?>,AnalysisSPILoader<?>>> expectedTypesSPILoaders = WeakIdentityMap.newConcurrentHashMap();
|
||||
|
||||
// Using this pattern, legacy analysis components from previous Solr versions are identified and delegated to SPI loader:
|
||||
private static final Pattern legacyAnalysisPattern =
|
||||
Pattern.compile("((\\Q"+base+".analysis.\\E)|(\\Q"+project+".\\E))([\\p{L}_$][\\p{L}\\p{N}_$]+?)(TokenFilter|Filter|Tokenizer|CharFilter)Factory");
|
||||
|
||||
/**
|
||||
* This method loads a class either with it's FQN or a short-name (solr.class-simplename or class-simplename).
|
||||
* It tries to load the class with the name that is given first and if it fails, it tries all the known
|
||||
|
@ -394,6 +406,33 @@ public class SolrResourceLoader implements ResourceLoader
|
|||
}
|
||||
}
|
||||
Class<? extends T> clazz = null;
|
||||
|
||||
// first try legacy analysis patterns, now replaced by Lucene's Analysis package:
|
||||
final Matcher m = legacyAnalysisPattern.matcher(cname);
|
||||
if (m.matches()) {
|
||||
log.trace("Trying to load class from analysis SPI");
|
||||
// retrieve the map of classLoader -> expectedType -> SPI from cache / regenerate cache
|
||||
Map<Class<?>,AnalysisSPILoader<?>> spiLoaders = expectedTypesSPILoaders.get(classLoader);
|
||||
if (spiLoaders == null) {
|
||||
spiLoaders = new IdentityHashMap<Class<?>,AnalysisSPILoader<?>>();
|
||||
spiLoaders.put(CharFilterFactory.class, CharFilterFactory.getSPILoader(classLoader));
|
||||
spiLoaders.put(TokenizerFactory.class, TokenizerFactory.getSPILoader(classLoader));
|
||||
spiLoaders.put(TokenFilterFactory.class, TokenFilterFactory.getSPILoader(classLoader));
|
||||
expectedTypesSPILoaders.put(classLoader, spiLoaders);
|
||||
}
|
||||
AnalysisSPILoader<? extends AbstractAnalysisFactory> loader = spiLoaders.get(expectedType);
|
||||
if (loader != null) {
|
||||
// it's a correct expected type for analysis! Let's go on!
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Class<? extends T> cl = (Class<? extends T>) loader.lookupClass(m.group(4));
|
||||
return clazz = cl;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// ok, we fall back to legacy loading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// first try cname == full name
|
||||
try {
|
||||
return Class.forName(cname, true, classLoader).asSubclass(expectedType);
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.apache.lucene.analysis.core.KeywordAnalyzer;
|
|||
import org.apache.lucene.analysis.core.KeywordTokenizerFactory;
|
||||
import org.apache.lucene.analysis.util.*;
|
||||
import org.apache.lucene.util.Version;
|
||||
import org.apache.solr.analysis.AnalysisPluginLoader;
|
||||
import org.apache.solr.analysis.TokenizerChain;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.util.DOMUtil;
|
||||
|
@ -263,15 +262,10 @@ public final class FieldTypePluginLoader
|
|||
|
||||
final ArrayList<CharFilterFactory> charFilters
|
||||
= new ArrayList<CharFilterFactory>();
|
||||
AnalysisPluginLoader<CharFilterFactory> charFilterLoader =
|
||||
new AnalysisPluginLoader<CharFilterFactory>
|
||||
AbstractPluginLoader<CharFilterFactory> charFilterLoader =
|
||||
new AbstractPluginLoader<CharFilterFactory>
|
||||
("[schema.xml] analyzer/charFilter", CharFilterFactory.class, false, false) {
|
||||
|
||||
@Override
|
||||
protected Class<? extends CharFilterFactory> lookupSPI(String name) {
|
||||
return CharFilterFactory.lookupClass(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(CharFilterFactory plugin, Node node) throws Exception {
|
||||
if( plugin != null ) {
|
||||
|
@ -301,15 +295,9 @@ public final class FieldTypePluginLoader
|
|||
|
||||
final ArrayList<TokenizerFactory> tokenizers
|
||||
= new ArrayList<TokenizerFactory>(1);
|
||||
AnalysisPluginLoader<TokenizerFactory> tokenizerLoader =
|
||||
new AnalysisPluginLoader<TokenizerFactory>
|
||||
AbstractPluginLoader<TokenizerFactory> tokenizerLoader =
|
||||
new AbstractPluginLoader<TokenizerFactory>
|
||||
("[schema.xml] analyzer/tokenizer", TokenizerFactory.class, false, false) {
|
||||
|
||||
@Override
|
||||
protected Class<? extends TokenizerFactory> lookupSPI(String name) {
|
||||
return TokenizerFactory.lookupClass(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(TokenizerFactory plugin, Node node) throws Exception {
|
||||
if( !tokenizers.isEmpty() ) {
|
||||
|
@ -344,15 +332,9 @@ public final class FieldTypePluginLoader
|
|||
final ArrayList<TokenFilterFactory> filters
|
||||
= new ArrayList<TokenFilterFactory>();
|
||||
|
||||
AnalysisPluginLoader<TokenFilterFactory> filterLoader =
|
||||
new AnalysisPluginLoader<TokenFilterFactory>("[schema.xml] analyzer/filter", TokenFilterFactory.class, false, false)
|
||||
AbstractPluginLoader<TokenFilterFactory> filterLoader =
|
||||
new AbstractPluginLoader<TokenFilterFactory>("[schema.xml] analyzer/filter", TokenFilterFactory.class, false, false)
|
||||
{
|
||||
|
||||
@Override
|
||||
protected Class<? extends TokenFilterFactory> lookupSPI(String name) {
|
||||
return TokenFilterFactory.lookupClass(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(TokenFilterFactory plugin, Node node) throws Exception {
|
||||
if( plugin != null ) {
|
||||
|
|
Loading…
Reference in New Issue