From dcc27e14b6d76e904e9e3ad4aeffcfb67f4e600f Mon Sep 17 00:00:00 2001 From: Erick Erickson Date: Wed, 8 May 2013 11:34:23 +0000 Subject: [PATCH] Fix for SOLR-4791, sharedLib in solr.xml doesn't work git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1480228 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/solr/core/CoreContainer.java | 2 +- .../java/org/apache/solr/core/SolrConfig.java | 16 ++++-- .../apache/solr/core/SolrResourceLoader.java | 35 +++---------- .../apache/solr/core/ResourceLoaderTest.java | 51 ++++++++++++++++++ .../apache/solr/core/TestCoreContainer.java | 52 +++++++++++++++++++ 5 files changed, 122 insertions(+), 34 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 22c93504c1a..61642662338 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -270,7 +270,7 @@ public class CoreContainer if (libDir != null) { File f = FileUtils.resolvePath(new File(dir), libDir); log.info("loading shared library: " + f.getAbsolutePath()); - loader.addToClassLoader(libDir); + loader.addToClassLoader(libDir, null, false); loader.reloadLuceneSPI(); } diff --git a/solr/core/src/java/org/apache/solr/core/SolrConfig.java b/solr/core/src/java/org/apache/solr/core/SolrConfig.java index e609844d481..fd887b9afd9 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java +++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java @@ -19,9 +19,9 @@ package org.apache.solr.core; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.IndexSchemaFactory; import org.apache.solr.util.DOMUtil; +import org.apache.solr.util.FileUtils; import org.apache.solr.util.RegexFileFilter; import org.apache.solr.handler.component.SearchComponent; import org.apache.solr.request.SolrRequestHandler; @@ -51,6 +51,7 @@ import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathConstants; +import java.io.File; import java.util.*; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -453,6 +454,7 @@ public class SolrConfig extends Config { if (nodes == null || nodes.getLength() == 0) return; log.info("Adding specified lib dirs to ClassLoader"); + SolrResourceLoader loader = getResourceLoader(); try { for (int i = 0; i < nodes.getLength(); i++) { @@ -464,16 +466,22 @@ public class SolrConfig extends Config { // :TODO: add support for a simpler 'glob' mutually exclusive of regex String regex = DOMUtil.getAttr(node, "regex"); FileFilter filter = (null == regex) ? null : new RegexFileFilter(regex); - getResourceLoader().addToClassLoader(baseDir, filter, false); + loader.addToClassLoader(baseDir, filter, false); } else if (null != path) { - getResourceLoader().addToClassLoader(path); + final File file = FileUtils.resolvePath(new File(loader.getInstanceDir()), path); + loader.addToClassLoader(file.getParent(), new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.equals(file); + } + }, false); } else { throw new RuntimeException( "lib: missing mandatory attributes: 'dir' or 'path'"); } } } finally { - getResourceLoader().reloadLuceneSPI(); + loader.reloadLuceneSPI(); } } } diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java index c10664f7e5e..6c19185b4e7 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java +++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java @@ -152,9 +152,11 @@ public class SolrResourceLoader implements ResourceLoader File base = FileUtils.resolvePath(new File(getInstanceDir()), baseDir); if (base != null && base.exists() && base.isDirectory()) { File[] files = base.listFiles(filter); - if (!quiet && (files == null || files.length == 0)) { - log.warn("No files added to classloader from lib: " - + baseDir + " (resolved as: " + base.getAbsolutePath() + ")."); + if (files == null || files.length == 0) { + if (!quiet) { + log.warn("No files added to classloader from lib: " + + baseDir + " (resolved as: " + base.getAbsolutePath() + ")."); + } } else { this.classLoader = replaceClassLoader(classLoader, base, filter); } @@ -165,35 +167,10 @@ public class SolrResourceLoader implements ResourceLoader } } } - - /** - * Adds the specific file/dir specified to the ClassLoader used by this - * ResourceLoader. This method MUST - * only be called prior to using this ResourceLoader to get any resources, otherwise - * it's behavior will be non-deterministic. You also have to {link #reloadLuceneSPI()} - * before using this ResourceLoader. - * - * @param path A jar file (or directory of classes) to be added to the classpath, - * will be resolved relative the instance dir. - */ - void addToClassLoader(final String path) { - final File file = FileUtils.resolvePath(new File(getInstanceDir()), path); - if (file.canRead()) { - this.classLoader = replaceClassLoader(classLoader, file.getParentFile(), - new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.equals(file); - } - }); - } else { - log.error("Can't find (or read) file to add to classloader: " + file); - } - } /** * Reloads all Lucene SPI implementations using the new classloader. - * This method must be called after {@link #addToClassLoader(String)} + * This method must be called after {@link #addToClassLoader(String, FileFilter, boolean)} * and {@link #addToClassLoader(String,FileFilter,boolean)} before using * this ResourceLoader. */ diff --git a/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java b/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java index 05d490a79c4..777aafb0ce2 100644 --- a/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java +++ b/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java @@ -22,6 +22,7 @@ import junit.framework.Assert; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.analysis.core.KeywordTokenizerFactory; import org.apache.lucene.analysis.ngram.NGramFilterFactory; +import org.apache.lucene.util._TestUtil; import org.apache.solr.common.SolrException; import org.apache.solr.handler.admin.LukeRequestHandler; import org.apache.solr.handler.component.FacetComponent; @@ -30,11 +31,15 @@ import org.apache.lucene.analysis.util.ResourceLoaderAware; import org.apache.solr.util.plugin.SolrCoreAware; import java.io.File; +import java.io.FileFilter; +import java.io.FileOutputStream; import java.io.InputStream; import java.nio.charset.CharacterCodingException; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; public class ResourceLoaderTest extends LuceneTestCase { @@ -131,4 +136,50 @@ public class ResourceLoaderTest extends LuceneTestCase assertTrue(expected.getCause() instanceof CharacterCodingException); } } + + public void testClassLoaderLibs() throws Exception { + File tmpRoot = _TestUtil.getTempDir("testClassLoaderLibs"); + + File lib = new File(tmpRoot, "lib"); + lib.mkdirs(); + + JarOutputStream jar1 = new JarOutputStream(new FileOutputStream(new File(lib, "jar1.jar"))); + jar1.putNextEntry(new JarEntry("aLibFile")); + jar1.closeEntry(); + jar1.close(); + + File otherLib = new File(tmpRoot, "otherLib"); + otherLib.mkdirs(); + + JarOutputStream jar2 = new JarOutputStream(new FileOutputStream(new File(otherLib, "jar2.jar"))); + jar2.putNextEntry(new JarEntry("explicitFile")); + jar2.closeEntry(); + jar2.close(); + JarOutputStream jar3 = new JarOutputStream(new FileOutputStream(new File(otherLib, "jar3.jar"))); + jar3.putNextEntry(new JarEntry("otherFile")); + jar3.closeEntry(); + jar3.close(); + + SolrResourceLoader loader = new SolrResourceLoader(tmpRoot.getAbsolutePath()); + + // ./lib is accessible by default + assertNotNull(loader.getClassLoader().getResource("aLibFile")); + + // file filter works (and doesn't add other files in the same dir) + final File explicitFileJar = new File(otherLib, "jar2.jar").getAbsoluteFile(); + loader.addToClassLoader("otherLib", + new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.equals(explicitFileJar); + } + }, false); + assertNotNull(loader.getClassLoader().getResource("explicitFile")); + assertNull(loader.getClassLoader().getResource("otherFile")); + + + // null file filter means accept all (making otherFile accessible) + loader.addToClassLoader("otherLib", null, false); + assertNotNull(loader.getClassLoader().getResource("otherFile")); + } } diff --git a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java index 5fc0dd5335f..d56f2bfc6ac 100644 --- a/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java +++ b/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java @@ -24,11 +24,14 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.io.FileUtils; import org.apache.lucene.util.IOUtils; +import org.apache.lucene.util._TestUtil; import org.apache.solr.SolrTestCaseJ4; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -334,6 +337,55 @@ public class TestCoreContainer extends SolrTestCaseJ4 { cc.shutdown(); } } + + @Test + public void testSharedLib() throws Exception { + File tmpRoot = _TestUtil.getTempDir("testSharedLib"); + + File lib = new File(tmpRoot, "lib"); + lib.mkdirs(); + + JarOutputStream jar1 = new JarOutputStream(new FileOutputStream(new File(lib, "jar1.jar"))); + jar1.putNextEntry(new JarEntry("defaultSharedLibFile")); + jar1.closeEntry(); + jar1.close(); + + File customLib = new File(tmpRoot, "customLib"); + customLib.mkdirs(); + + JarOutputStream jar2 = new JarOutputStream(new FileOutputStream(new File(customLib, "jar2.jar"))); + jar2.putNextEntry(new JarEntry("customSharedLibFile")); + jar2.closeEntry(); + jar2.close(); + + FileUtils.writeStringToFile(new File(tmpRoot, "default-lib-solr.xml"), "", "UTF-8"); + FileUtils.writeStringToFile(new File(tmpRoot, "explicit-lib-solr.xml"), "", "UTF-8"); + FileUtils.writeStringToFile(new File(tmpRoot, "custom-lib-solr.xml"), "", "UTF-8"); + + final CoreContainer cc1 = new CoreContainer(tmpRoot.getAbsolutePath()); + cc1.load(tmpRoot.getAbsolutePath(), new File(tmpRoot, "default-lib-solr.xml")); + try { + cc1.loader.openResource("defaultSharedLibFile").close(); + } finally { + cc1.shutdown(); + } + + final CoreContainer cc2 = new CoreContainer(tmpRoot.getAbsolutePath()); + cc2.load(tmpRoot.getAbsolutePath(), new File(tmpRoot, "explicit-lib-solr.xml")); + try { + cc2.loader.openResource("defaultSharedLibFile").close(); + } finally { + cc2.shutdown(); + } + + final CoreContainer cc3 = new CoreContainer(tmpRoot.getAbsolutePath()); + cc3.load(tmpRoot.getAbsolutePath(), new File(tmpRoot, "custom-lib-solr.xml")); + try { + cc3.loader.openResource("customSharedLibFile").close(); + } finally { + cc3.shutdown(); + } + } private static final String EMPTY_SOLR_XML ="\n" + "\n" +