SaidbakR
SaidbakR

Reputation: 13534

two versions of solr on tomcat

I have got installed two versions of solr on Tomcat 6, 1.3 and 4.7 each of them are accessible but in the tomcat configuration's tab Java -Dsolr.solr.home=C:\Solr\solr where this path is the path of 1.3 However, I have the 4.7 on E:\new-solr.

When I try to create new core it created well but it disappeared after restarting Tomcat. I belive that the missing of correct Solr home is the reason. So, is there a way to set multiple solr home in Java properties of Tomcat?

Edit: When I run Tomcat with -Dsolr.solr.home=C:\Solr\solr I have got errors about missing cores in Solr 4.7 version where those cores works fine in Solr 1.3.

SolrCore Initialization Failures archive: org.apache.solr.common.SolrException:org.apache.solr.common.SolrException: Could not load config file c:\solr\solr\archive\solrconfig.xml

Upvotes: 1

Views: 804

Answers (2)

Arjan
Arjan

Reputation: 23529

Solr's SolrResourceLoader#locateSolrHome first tries JNDI and then system properties to find its settings. As -D system properties are shared between all applications in a single Tomcat instance, those cannot be used to configure multiple Solr instances.

If for some reason one cannot use JNDI (like <Environment name="solr/home" ...> in XML files), or a single instance with multiple cores, then one could wrap the Solr WAR into one's own application and use a servlet context listener to (temporarily) change the system properties while starting.

This surely is a hack, and relies on Tomcat not starting applications in parallel, and on Solr only reading the system properties on startup. I've tested this to work nicely, but still it's probably only suitable for testing purposes.

Again, this first of all needs one to wrap Solr into one's own application. Next, create a folder /some/config with a sub folder for each instance, matching its context name. In each sub folder create a custom.properties file:

# This file /some/config/[servlet-context-name]/custom.properties is used
# if Tomcat is started with:
#   -Dcustom.config.dir=/some/config
# ...and then (temporarily) overwrites any system properties specified below:

solr.solr.home=/some/other/folder/conf
solr.data.dir=/some/other/folder/data

To merge system properties based on some key-values in a properties file:

/**
 * Tries to find the given file and merges its properties into the existing
 * system properties.
 *
 * @param configFile
 *            full path of a property file
 * @return {@code true} if the file was found and merged; {@code false}
 *         otherwise
 */
private boolean mergeSystemProperties(final String configFile) {

    try (final FileInputStream is = new FileInputStream(configFile)) {

        final Properties custom = new Properties();
        custom.load(is);

        for (final Map.Entry<Object, Object> prop : custom.entrySet()) {
            LOG.info("Setting {}={}", prop.getKey(), prop.getValue());
            System.setProperty((String)prop.getKey(), (String)prop.getValue());
        }

        return true;

    } catch (final FileNotFoundException e) {
        LOG.info("Could not find custom properties: {}", configFile);
    } catch (final IOException e) {
        LOG.error("Failed to read custom properties: " + configFile, e);
    }
    return false;
}

This can be used in a listener:

public class TestConfigContextListener implements ServletContextListener {
    private static final Logger LOG = ...
    private static final String PROP_DIR = "custom.config.dir";
    private static final String FILE_NAME = "custom.properties";

    @Override
    public void contextInitialized(final ServletContextEvent event) {

        final String configDir = System.getProperty(PROP_DIR);    
        if (configDir == null) {
            LOG.info("No value for -D{}; not reading custom config", PROP_DIR);
        } else {
            LOG.info("Custom config dir: -D{}={}", PROP_DIR, configDir);
            final ServletContext context = event.getServletContext();

            // Either "" for the root, or "/some-path" otherwise
            final String contextPath = context.getContextPath();
            if (!contextPath.isEmpty()) {
                if (mergeSystemProperties(configDir + File.separator
                  + contextPath.substring(1, contextPath.length())
                  + File.separator + FILE_NAME)) {
                    // We found the configuration in a subfolder matching the
                    // specific contextPath; done.
                    return;
                }
            }

            // Root context, or no configuration in a subfolder matching the
            // specific contextPath; try to load from configDir itself:
            mergeSystemProperties(configDir + File.separator + FILE_NAME);
        }
    }
    ...
}

...with in web.xml:

 <!-- 
   Tries to read a property file to set/override system properties just before
   Solr is initialized, sort of allowing to run multiple instances with
   different settings, IF THEY ARE NOT STARTED SIMULTANEOUSLY.
 -->
 <listener>
   <listener-class>net.example.TestConfigContextListener</listener-class>
 </listener>

Final notes: though one could use <env-entry> in web.xml for "fake" JNDI entries, using ServletContext#setInitParameter to change those in the context listener has no effect. Also, the JNDI context java:comp/env is read-only hence cannot be changed from code. So one really needs to fall back to (temporarily) setting the system properties.

Upvotes: 1

nikhil500
nikhil500

Reputation: 3450

Looks like you are passing in the value of solr home using JAVA_OPTS. You need to edit server.xml and add the appropriate Solr home to Context. The following example is from SolrTomcat page on the Solr wiki.

<Context docBase="/opt/solr/example/solr/solr.war" debug="0" crossContext="true">
  <Environment name="solr/home" type="java.lang.String" value="/opt/solr/example/solr" override="true"/>
</Context>

Upvotes: 1

Related Questions