diff --git a/CHANGES.txt b/CHANGES.txt index d0cc42b8e0f..5c60b76c732 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -179,6 +179,9 @@ Optimizations 6. SOLR-971: Replace StringBuffer with StringBuilder for instances that do not require thread-safety. (Kay Kay via shalin) + 7. SOLR-921: SolrResourceLoader must cache short class name vs fully qualified classname + (Noble Paul, hossman via shalin) + Bug Fixes ---------------------- 1. SOLR-774: Fixed logging level display (Sean Timm via Otis Gospodnetic) diff --git a/src/java/org/apache/solr/core/SolrResourceLoader.java b/src/java/org/apache/solr/core/SolrResourceLoader.java index 2ce4423776e..53fc64aeef4 100644 --- a/src/java/org/apache/solr/core/SolrResourceLoader.java +++ b/src/java/org/apache/solr/core/SolrResourceLoader.java @@ -23,11 +23,12 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.Charset; @@ -50,7 +51,6 @@ import org.apache.solr.schema.FieldType; import org.apache.solr.update.processor.UpdateRequestProcessorFactory; import org.apache.solr.util.plugin.ResourceLoaderAware; import org.apache.solr.util.plugin.SolrCoreAware; -import org.apache.solr.spelling.SpellingQueryConverter; /** * @since solr 1.3 @@ -258,9 +258,37 @@ public class SolrResourceLoader implements ResourceLoader return lines; } + /* + * A static map of short class name to fully qualified class name + */ + private static Map classNameCache = new ConcurrentHashMap(); + + /** + * 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 + * solr packages. This method caches the FQN of a short-name in a static map in-order to make subsequent lookups + * for the same class faster. The caching is done only if the class is loaded by the webapp classloader and it + * is loaded using a shortname. + * + * @param cname The name or the short name of the class. + * @param subpackages the packages to be tried if the cnams starts with solr. + * @return the loaded class. An exception is thrown if it fails + */ public Class findClass(String cname, String... subpackages) { - if (subpackages.length==0) subpackages = packages; - + if (subpackages.length == 0 || subpackages == packages) { + subpackages = packages; + String c = classNameCache.get(cname); + if(c != null) { + try { + return Class.forName(c, true, classLoader); + } catch (ClassNotFoundException e) { + //this is unlikely + log.error("Unable to load cached class-name : "+ c +" for shortname : "+cname + e); + } + + } + } + Class clazz = null; // first try cname == full name try { return Class.forName(cname, true, classLoader); @@ -273,13 +301,23 @@ public class SolrResourceLoader implements ResourceLoader try { String name = base + '.' + subpackage + newName; log.trace("Trying class name " + name); - return Class.forName(name, true, classLoader); + return clazz = Class.forName(name,true,classLoader); } catch (ClassNotFoundException e1) { // ignore... assume first exception is best. } } throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "Error loading class '" + cname + "'", e, false); + }finally{ + //cache the shortname vs FQN if it is loaded by the webapp classloader and it is loaded + // using a shortname + if ( clazz != null && + clazz.getClassLoader() == SolrResourceLoader.class.getClassLoader() && + !cname.equals(clazz.getName()) && + (subpackages.length == 0 || subpackages == packages)) { + //store in the cache + classNameCache.put(cname, clazz.getName()); + } } }