You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by sh...@apache.org on 2008/08/23 18:25:19 UTC

svn commit: r688359 - in /lucene/solr/trunk: ./ client/java/solrj/test/org/apache/solr/client/solrj/embedded/ src/java/org/apache/solr/common/util/ src/java/org/apache/solr/core/ src/test/test-files/solr/shared/ src/test/test-files/solr/shared/conf/

Author: shalin
Date: Sat Aug 23 09:25:19 2008
New Revision: 688359

URL: http://svn.apache.org/viewvc?rev=688359&view=rev
Log:
SOLR-716 -- Added support for properties in configuration files.

Added:
    lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java   (with props)
    lucene/solr/trunk/src/test/test-files/solr/shared/
    lucene/solr/trunk/src/test/test-files/solr/shared/conf/
    lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml   (with props)
    lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml   (with props)
    lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt   (with props)
    lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt   (with props)
    lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml   (with props)
Modified:
    lucene/solr/trunk/CHANGES.txt
    lucene/solr/trunk/src/java/org/apache/solr/common/util/DOMUtil.java
    lucene/solr/trunk/src/java/org/apache/solr/core/Config.java
    lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
    lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java
    lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java

Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=688359&r1=688358&r2=688359&view=diff
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Sat Aug 23 09:25:19 2008
@@ -345,6 +345,10 @@
 
 69. SOLR-506: Emitting HTTP Cache headers can be enabled or disabled through configuration
               on a per-handler basis (shalin)
+
+70. SOLR-716: Added support for properties in configuration files. Properties can be specified in solr.xml
+              and can be used in solrconfig.xml and schema.xml
+              (Henri Biestro, hossman, ryan, shalin) 
     
 Changes in runtime behavior
  1. SOLR-559: use Lucene updateDocument, deleteDocuments methods.  This

Added: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java?rev=688359&view=auto
==============================================================================
--- lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java (added)
+++ lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java Sat Aug 23 09:25:19 2008
@@ -0,0 +1,168 @@
+/**
+ * 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.
+ */
+
+package org.apache.solr.client.solrj.embedded;
+
+import static junit.framework.Assert.assertEquals;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServer;
+import org.apache.solr.client.solrj.request.CoreAdminRequest;
+import org.apache.solr.client.solrj.request.QueryRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.client.solrj.request.UpdateRequest.ACTION;
+import org.apache.solr.client.solrj.response.CoreAdminResponse;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.util.AbstractSolrTestCase;
+import org.junit.After;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.logging.Logger;
+
+/**
+ * @version $Id$
+ * @since solr 1.3
+ */
+public class TestSolrProperties {
+  protected static Logger log = Logger.getLogger(TestSolrProperties.class.getName());
+  protected CoreContainer cores = null;
+
+  public String getSolrHome() {
+    return "solr/shared";
+  }
+
+  public String getSolrXml() {
+    return "solr.xml";
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    System.setProperty("solr.solr.home", getSolrHome());
+
+    log.info("pwd: " + (new File(".")).getAbsolutePath());
+    File home = new File(getSolrHome());
+    File f = new File(home, "solr.xml");
+    cores = new CoreContainer(getSolrHome(), f);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (cores != null)
+      cores.shutdown();
+    File dataDir = new File(getSolrHome() + "/data");
+    String skip = System.getProperty("solr.test.leavedatadir");
+    if (null != skip && 0 != skip.trim().length()) {
+      log.info("NOTE: per solr.test.leavedatadir, dataDir will not be removed: " + dataDir.getAbsolutePath());
+    } else {
+      if (!AbstractSolrTestCase.recurseDelete(dataDir)) {
+        log.warning("!!!! WARNING: best effort to remove " + dataDir.getAbsolutePath() + " FAILED !!!!!");
+      }
+    }
+    File persistedFile = new File("solr-persist.xml");
+    persistedFile.delete();
+  }
+
+  protected SolrServer getSolrCore0() {
+    return new EmbeddedSolrServer(cores, "core0");
+  }
+
+
+  protected SolrServer getSolrCore1() {
+    return new EmbeddedSolrServer(cores, "core1");
+  }
+
+  protected SolrServer getSolrAdmin() {
+    return new EmbeddedSolrServer(cores, "core0");
+  }
+
+  protected SolrServer getSolrCore(String name) {
+    return new EmbeddedSolrServer(cores, name);
+  }
+
+  @Test
+  public void testProperties() throws Exception {
+    UpdateRequest up = new UpdateRequest();
+    up.setAction(ACTION.COMMIT, true, true);
+    up.deleteByQuery("*:*");
+    up.process(getSolrCore0());
+    up.process(getSolrCore1());
+    up.clear();
+
+    // Add something to each core
+    SolrInputDocument doc = new SolrInputDocument();
+    doc.setField("id", "AAA");
+    doc.setField("core0", "yup stopfra stopfrb stopena stopenb");
+
+    // Add to core0
+    up.add(doc);
+    up.process(getSolrCore0());
+
+    // You can't add it to core1
+    try {
+      up.process(getSolrCore1());
+      fail("Can't add core0 field to core1!");
+    }
+    catch (Exception ex) {
+    }
+
+    // Add to core1
+    doc.setField("id", "BBB");
+    doc.setField("core1", "yup stopfra stopfrb stopena stopenb");
+    doc.removeField("core0");
+    up.add(doc);
+    up.process(getSolrCore1());
+
+    // You can't add it to core1
+    try {
+      up.process(getSolrCore0());
+      fail("Can't add core1 field to core0!");
+    }
+    catch (Exception ex) {
+    }
+
+    // now Make sure AAA is in 0 and BBB in 1
+    SolrQuery q = new SolrQuery();
+    QueryRequest r = new QueryRequest(q);
+    q.setQuery("id:AAA");
+    assertEquals(1, r.process(getSolrCore0()).getResults().size());
+    assertEquals(0, r.process(getSolrCore1()).getResults().size());
+
+    // Now test Changing the default core
+    assertEquals(1, getSolrCore0().query(new SolrQuery("id:AAA")).getResults().size());
+    assertEquals(0, getSolrCore0().query(new SolrQuery("id:BBB")).getResults().size());
+
+    assertEquals(0, getSolrCore1().query(new SolrQuery("id:AAA")).getResults().size());
+    assertEquals(1, getSolrCore1().query(new SolrQuery("id:BBB")).getResults().size());
+
+    // Now test reloading it should have a newer open time
+    String name = "core0";
+    SolrServer coreadmin = getSolrAdmin();
+    CoreAdminResponse mcr = CoreAdminRequest.getStatus(name, coreadmin);
+    long before = mcr.getStartTime(name).getTime();
+    CoreAdminRequest.reloadCore(name, coreadmin);
+
+    mcr = CoreAdminRequest.getStatus(name, coreadmin);
+    long after = mcr.getStartTime(name).getTime();
+    assertTrue("should have more recent time: " + after + "," + before, after > before);
+
+    mcr = CoreAdminRequest.persist("solr-persist.xml", coreadmin);
+  }
+}

Propchange: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/solr/trunk/src/java/org/apache/solr/common/util/DOMUtil.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/common/util/DOMUtil.java?rev=688359&r1=688358&r2=688359&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/common/util/DOMUtil.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/common/util/DOMUtil.java Sat Aug 23 09:25:19 2008
@@ -17,11 +17,7 @@
 
 package org.apache.solr.common.util;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.solr.common.SolrException;
 import org.w3c.dom.NamedNodeMap;
@@ -205,17 +201,17 @@
       break;
 
     case Node.ATTRIBUTE_NODE: /* fall through */
-      /* Putting Attribute nodes in this section does not exactly 
-         match the definition of how textContent should behave 
-         according to the DOM Level-3 Core documentation - which 
-         specifies that the Attr's children should have their 
-         textContent concated (Attr's can have a single child which 
+      /* Putting Attribute nodes in this section does not exactly
+         match the definition of how textContent should behave
+         according to the DOM Level-3 Core documentation - which
+         specifies that the Attr's children should have their
+         textContent concated (Attr's can have a single child which
          is either Text node or an EntityRefrence).  In practice,
-         DOM implementations do not seem to use child nodes of 
+         DOM implementations do not seem to use child nodes of
          Attributes, storing the "text" directly as the nodeValue.
-         Fortunately, the DOM Spec indicates that when Attr.nodeValue 
-         is read, it should return the nodeValue from the child Node, 
-         so this approach should work both for strict implementations, 
+         Fortunately, the DOM Spec indicates that when Attr.nodeValue
+         is read, it should return the nodeValue from the child Node,
+         so this approach should work both for strict implementations,
          and implementations actually encountered.
       */
     case Node.TEXT_NODE: /* fall through */
@@ -242,6 +238,19 @@
    * @param node DOM node to walk for substitutions
    */
   public static void substituteSystemProperties(Node node) {
+    substituteProperties(node, null);
+  }
+
+  /**
+   * Replaces ${property[:default value]} references in all attributes
+   * and text nodes of supplied node.  If the property is not defined neither in the
+   * given Properties instance nor in System.getProperty and no
+   * default value is provided, a runtime exception is thrown.
+   *
+   * @param node DOM node to walk for substitutions
+   * @param properties the Properties instance from which a value can be looked up
+   */
+  public static void substituteProperties(Node node, Properties properties) {
     // loop through child nodes
     Node child;
     Node next = node.getFirstChild();
@@ -252,15 +261,15 @@
 
       // handle child by node type
       if (child.getNodeType() == Node.TEXT_NODE) {
-        child.setNodeValue(substituteSystemProperty(child.getNodeValue()));
+        child.setNodeValue(substituteProperty(child.getNodeValue(), properties));
       } else if (child.getNodeType() == Node.ELEMENT_NODE) {
         // handle child elements with recursive call
         NamedNodeMap attributes = child.getAttributes();
         for (int i = 0; i < attributes.getLength(); i++) {
           Node attribute = attributes.item(i);
-          attribute.setNodeValue(substituteSystemProperty(attribute.getNodeValue()));
+          attribute.setNodeValue(substituteProperty(attribute.getNodeValue(), properties));
         }
-        substituteSystemProperties(child);
+        substituteProperties(child, properties);
       }
     }
   }
@@ -269,7 +278,7 @@
    * This method borrowed from Ant's PropertyHelper.replaceProperties:
    *   http://svn.apache.org/repos/asf/ant/core/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
    */
-  private static String substituteSystemProperty(String value) {
+  private static String substituteProperty(String value, Properties coreProperties) {
     if (value == null || value.indexOf('$') == -1) {
       return value;
     }
@@ -292,7 +301,12 @@
           defaultValue = propertyName.substring(colon_index + 1);
           propertyName = propertyName.substring(0,colon_index);
         }
-        fragment = System.getProperty(propertyName,defaultValue);
+        if (coreProperties != null) {
+          fragment = coreProperties.getProperty(propertyName);
+        }
+        if (fragment == null) {
+          fragment = System.getProperty(propertyName, defaultValue);
+        }
         if (fragment == null) {
           throw new SolrException( SolrException.ErrorCode.SERVER_ERROR, "No system property or default value specified for " + propertyName);
         }

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/Config.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/Config.java?rev=688359&r1=688358&r2=688359&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/Config.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/Config.java Sat Aug 23 09:25:19 2008
@@ -102,7 +102,7 @@
       javax.xml.parsers.DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
       doc = builder.parse(lis);
 
-    	DOMUtil.substituteSystemProperties(doc);
+        DOMUtil.substituteProperties(doc, loader.getCoreProperties());
     } catch( SolrException e ){
     	SolrException.log(log,"Error in "+name,e);
     	throw e;
@@ -111,7 +111,7 @@
       if (lis != is)  lis.close();
     }
   }
-  
+
   /**
    * @since solr 1.3
    */

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java?rev=688359&r1=688358&r2=688359&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java Sat Aug 23 09:25:19 2008
@@ -30,6 +30,8 @@
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpressionException;
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.DOMUtil;
@@ -60,9 +62,14 @@
   protected ClassLoader libLoader = null;
   protected SolrResourceLoader loader = null;
   protected java.lang.ref.WeakReference<SolrCore> adminCore = null;
+  protected Properties containerProperties;
   
   public CoreContainer() {
   }
+
+  public Properties getContainerProperties() {
+    return containerProperties;
+  }
   
   // Helper class to initialize the CoreContainer
   public static class Initializer {
@@ -178,6 +185,13 @@
         coreAdminHandler = this.createMultiCoreHandler();
       }
 
+      try {
+        containerProperties = readProperties(cfg, ((NodeList) cfg.evaluate("solr", XPathConstants.NODESET)).item(0));
+      } catch (Throwable e) {
+        SolrConfig.severeErrors.add(e);
+        SolrException.logOnce(log,null,e);
+      }
+
       NodeList nodes = (NodeList)cfg.evaluate("solr/cores/core", XPathConstants.NODESET);
 
       for (int i=0; i<nodes.getLength(); i++) {
@@ -187,6 +201,7 @@
           List<String> aliases = StrUtils.splitSmart(names,',');
           String name = aliases.get(0);
           CoreDescriptor p = new CoreDescriptor(this, name, DOMUtil.getAttr(node, "instanceDir", null));
+          p.setCoreProperties(readProperties(cfg, node));
 
           // deal with optional settings
           String opt = DOMUtil.getAttr(node, "config", null);
@@ -220,7 +235,18 @@
       }
     }
   }
-  
+
+  private Properties readProperties(Config cfg, Node node) throws XPathExpressionException {
+    XPath xpath = cfg.getXPath();
+    NodeList props = (NodeList) xpath.evaluate("property", node, XPathConstants.NODESET);
+    Properties properties = new Properties();
+    for (int i=0; i<props.getLength(); i++) {
+      Node prop = props.item(i);
+      properties.setProperty(DOMUtil.getAttr(prop, "name"), DOMUtil.getAttr(prop, "value"));
+    }
+    return properties;
+  }
+
   /**
    * Stops all cores.
    */
@@ -291,7 +317,7 @@
     String instanceDir = idir.getPath();
     
     // Initialize the solr config
-    SolrResourceLoader solrLoader = new SolrResourceLoader(instanceDir, libLoader);
+    SolrResourceLoader solrLoader = new SolrResourceLoader(instanceDir, libLoader, dcore.getCoreProperties());
     SolrConfig config = new SolrConfig(solrLoader, dcore.getConfigName(), null);
     IndexSchema schema = new IndexSchema(config, dcore.getSchemaName(), null);
     SolrCore core = new SolrCore(dcore.getName(), null, config, schema, dcore);
@@ -395,7 +421,8 @@
 
   
   /** Gets a core by name and increase its refcount.
-   * @see SolrCore.open() @see SolrCore.close()
+   * @see SolrCore#open() 
+   * @see SolrCore#close() 
    * @param name the core name
    * @return the core if found
    */
@@ -563,6 +590,10 @@
     writer.write('\'');
     writer.write(">\n");
 
+    if (containerProperties != null && !containerProperties.isEmpty())  {
+      writeProperties(writer, containerProperties);
+    }
+
     Map<SolrCore, LinkedList<String>> aliases = new HashMap<SolrCore,LinkedList<String>>();
 
     synchronized(cores) {
@@ -609,9 +640,25 @@
       XML.escapeAttributeValue(opt, writer);
       writer.write('\'');
     }
-    writer.write("/>\n"); // core
+    if (dcore.getCoreProperties() == null || dcore.getCoreProperties().isEmpty())
+      writer.write("/>\n"); // core
+    else  {
+      writer.write(">\n");
+      writeProperties(writer, dcore.getCoreProperties());
+      writer.write("</core>");
+    }
   }
-  
+
+  private void writeProperties(Writer writer, Properties props) throws IOException {
+    for (Map.Entry<Object, Object> entry : props.entrySet()) {
+      writer.write("<property name='");
+      XML.escapeAttributeValue(entry.getKey().toString(), writer);
+      writer.write("' value='");
+      XML.escapeAttributeValue(entry.getValue().toString(), writer);
+      writer.write("' />\n");
+    }
+  }
+
   /** Copies a src file to a dest file:
    *  used to circumvent the platform discrepancies regarding renaming files.
    */

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java?rev=688359&r1=688358&r2=688359&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java Sat Aug 23 09:25:19 2008
@@ -17,6 +17,7 @@
 
 package org.apache.solr.core;
 
+import java.util.Properties;
 
 /**
  * A Solr core descriptor
@@ -29,6 +30,7 @@
   protected String configName;
   protected String schemaName;
   private final CoreContainer coreContainer;
+  private Properties coreProperties;
 
   public CoreDescriptor(CoreContainer coreContainer, String name, String instanceDir) {
     this.coreContainer = coreContainer;
@@ -52,6 +54,15 @@
     this.name = descr.name;
     coreContainer = descr.coreContainer;
   }
+
+  private Properties initImplicitProperties() {
+    Properties implicitProperties = new Properties(coreContainer.getContainerProperties());
+    implicitProperties.setProperty("solr.core.name", name);
+    implicitProperties.setProperty("solr.core.instanceDir", instanceDir);
+    implicitProperties.setProperty("solr.core.configName", configName);
+    implicitProperties.setProperty("solr.core.schemaName", schemaName);
+    return implicitProperties;
+  }
   
   /**@return the default config name. */
   public String getDefaultConfigName() {
@@ -105,4 +116,32 @@
   public CoreContainer getCoreContainer() {
     return coreContainer;
   }
+
+  /**
+   * Get this core's properties
+   * 
+   * @return a shallow copy of this core's properties
+   */
+  public Properties getCoreProperties() {
+    Properties p = new Properties();
+    if (coreProperties != null)
+      p.putAll(coreProperties);
+    return p;
+  }
+
+  /**
+   * Set this core's properties. Please note that some implicit values will be added to the
+   * Properties instance passed into this method. This means that the Properties instance
+   * set to this method will have different (less) key/value pairs than the Properties
+   * instance returned by #getCoreProperties method.
+   * 
+   * @param coreProperties
+   */
+  public void setCoreProperties(Properties coreProperties) {
+    if (this.coreProperties == null) {
+      Properties p = initImplicitProperties();
+      this.coreProperties = new Properties(p);
+      this.coreProperties.putAll(coreProperties);
+    }
+  }
 }

Modified: lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java?rev=688359&r1=688358&r2=688359&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/core/SolrResourceLoader.java Sat Aug 23 09:25:19 2008
@@ -27,10 +27,7 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.logging.Logger;
 import java.nio.charset.Charset;
 
@@ -71,6 +68,8 @@
   private final List<ResourceLoaderAware> waitingForResources = new ArrayList<ResourceLoaderAware>();
   private static final Charset UTF_8 = Charset.forName("UTF-8");
 
+  private final Properties coreProperties;
+
   /**
    * <p>
    * This loader will delegate to the context classloader when possible,
@@ -79,7 +78,7 @@
    * If the instance directory is not specified (=null), SolrResourceLoader#locateInstanceDir will provide one.
    * <p>
    */
-  public SolrResourceLoader( String instanceDir, ClassLoader parent )
+  public SolrResourceLoader( String instanceDir, ClassLoader parent, Properties coreProperties )
   {
     if( instanceDir == null ) {
       this.instanceDir = SolrResourceLoader.locateInstanceDir();
@@ -88,6 +87,20 @@
     }
     log.info("Solr home set to '" + this.instanceDir + "'");
     this.classLoader = createClassLoader(new File(this.instanceDir + "lib/"), parent);
+    this.coreProperties = coreProperties;
+  }
+
+  /**
+   * <p>
+   * This loader will delegate to the context classloader when possible,
+   * otherwise it will attempt to resolve resources using any jar files
+   * found in the "lib/" directory in the specified instance directory.
+   * If the instance directory is not specified (=null), SolrResourceLoader#locateInstanceDir will provide one.
+   * <p>
+   */
+  public SolrResourceLoader( String instanceDir, ClassLoader parent )
+  {
+    this(instanceDir, parent, null);
   }
     
   static ClassLoader createClassLoader(File f, ClassLoader loader) {
@@ -113,7 +126,7 @@
 
   public SolrResourceLoader( String instanceDir )
   {
-    this( instanceDir, null );
+    this( instanceDir, null, null );
   }
   
   /** Ensures a directory name allways ends with a '/'. */
@@ -129,6 +142,10 @@
     return dataDir;
   }
 
+  public Properties getCoreProperties() {
+    return coreProperties;
+  }
+
   /** Opens a schema resource by its name.
    * Override this method to customize loading schema resources.
    *@return the stream for the named schema

Added: lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml?rev=688359&view=auto
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml (added)
+++ lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml Sat Aug 23 09:25:19 2008
@@ -0,0 +1,69 @@
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+
+<schema name="example core ${l10n}" version="1.1">
+  <types>
+    <fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
+    <fieldType name="text-FR" class="solr.TextField" positionIncrementGap="100">
+      <analyzer type="index">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords-fr.txt"/>
+        <filter class="solr.StandardFilterFactory"/>
+        <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords-fr.txt"/>
+        <filter class="solr.StandardFilterFactory"/>
+        <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
+      </analyzer>
+    </fieldType>
+    <fieldType name="text-EN" class="solr.TextField" positionIncrementGap="100">
+      <analyzer type="index">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords-en.txt"/>
+        <filter class="solr.StandardFilterFactory"/>
+        <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords-en.txt"/>
+        <filter class="solr.StandardFilterFactory"/>
+        <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
+      </analyzer>
+    </fieldType>
+  </types>
+
+  <fields>
+    <!-- general -->
+    <field name="id" type="string" indexed="true" stored="true" multiValued="false" required="true"/>
+    <field name="type" type="string" indexed="true" stored="true" multiValued="false"/>
+    <field name="name" type="string" indexed="true" stored="true" multiValued="false"/>
+    <field name="${ctlField}" type="text-${l10n}" indexed="true" stored="true" multiValued="true"/>
+  </fields>
+
+  <!-- field to use to determine and enforce document uniqueness. -->
+  <uniqueKey>id</uniqueKey>
+
+  <!-- field for the QueryParser to use when an explicit fieldname is absent -->
+  <defaultSearchField>name</defaultSearchField>
+
+  <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
+  <solrQueryParser defaultOperator="OR"/>
+</schema>
+

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/schema.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml?rev=688359&view=auto
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml (added)
+++ lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml Sat Aug 23 09:25:19 2008
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+ This is a stripped down config file used for a simple example...  
+ It is *not* a good example to work from. 
+-->
+<config>
+  <dataDir>${solr.solr.home}/data/${l10n}-${version}</dataDir>
+
+
+  <updateHandler class="solr.DirectUpdateHandler2" />
+
+  <requestDispatcher handleSelect="true" >
+    <requestParsers enableRemoteStreaming="false" multipartUploadLimitInKB="2048" />
+  </requestDispatcher>
+  
+  <requestHandler name="standard" class="solr.StandardRequestHandler" default="true" />
+  <requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
+  <requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
+      
+  <!-- config for the admin interface --> 
+  <admin>
+    <defaultQuery>solr</defaultQuery>
+  </admin>
+
+</config>
+

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/solrconfig.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt?rev=688359&view=auto
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt (added)
+++ lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt Sat Aug 23 09:25:19 2008
@@ -0,0 +1,16 @@
+# 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.
+stopena
+stopenb

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-en.txt
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt?rev=688359&view=auto
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt (added)
+++ lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt Sat Aug 23 09:25:19 2008
@@ -0,0 +1,16 @@
+# 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.
+stopfra
+stopfrb

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/conf/stopwords-fr.txt
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml?rev=688359&view=auto
==============================================================================
--- lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml (added)
+++ lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml Sat Aug 23 09:25:19 2008
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<!--
+ All (relative) paths are relative to the installation path
+  
+  persistent: Save changes made via the API to this file
+  sharedLib: path to a lib directory that will be shared across all cores
+-->
+<solr persistent="true">
+  <property name="version" value="1.3"/>
+  <property name="lang" value="english, french"/>
+
+  <!--
+  adminPath: RequestHandler path to manage cores.  
+    If 'null' (or absent), cores will not be manageable via REST
+  -->
+  <cores adminPath="/admin/cores">
+    <core name="core0" instanceDir="./">
+      <property name="version" value="3.5"/>
+      <property name="l10n" value="EN"/>
+      <property name="ctlField" value="core0"/>
+      <property name="comment" value="This is a sample"/>
+    </core>
+    <core name="core1" instanceDir="./">
+      <property name="version" value="2.4"/>
+      <property name="l10n" value="FR"/>
+      <property name="ctlField" value="core1"/>
+      <property name="comment" value="Ceci est un exemple"/>
+    </core>
+  </cores>
+</solr>

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: lucene/solr/trunk/src/test/test-files/solr/shared/solr.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL