org.apache.solr.core.Config.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.solr.core.Config.java

Source

/**
 * 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.core;

import org.apache.lucene.util.Version;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.DOMUtil;
import org.apache.solr.common.util.SystemIdResolver;
import org.apache.solr.common.util.XMLErrorLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.apache.commons.io.IOUtils;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @version $Id: Config.java 1075090 2011-02-27 17:20:30Z uschindler $
 */
public class Config {
    public static final Logger log = LoggerFactory.getLogger(Config.class);
    private static final XMLErrorLogger xmllog = new XMLErrorLogger(log);

    static final XPathFactory xpathFactory = XPathFactory.newInstance();

    private final Document doc;
    private final String prefix;
    private final String name;
    private final SolrResourceLoader loader;

    /**
     * @deprecated Use {@link #Config(SolrResourceLoader, String, InputSource, String)} instead. 
     */
    @Deprecated
    public Config(String name, InputStream is, String prefix)
            throws ParserConfigurationException, IOException, SAXException {
        this(null, name, new InputSource(is), prefix);
    }

    /**
     * Builds a config from a resource name with no xpath prefix.
     * @param loader
     * @param name
     * @throws javax.xml.parsers.ParserConfigurationException
     * @throws java.io.IOException
     * @throws org.xml.sax.SAXException
     */
    public Config(SolrResourceLoader loader, String name)
            throws ParserConfigurationException, IOException, SAXException {
        this(loader, name, (InputSource) null, null);
    }

    /**
     * Builds a config:
     * <p>
     * Note that the 'name' parameter is used to obtain a valid input stream if no valid one is provided through 'is'.
     * If no valid stream is provided, a valid SolrResourceLoader instance should be provided through 'loader' so
     * the resource can be opened (@see SolrResourceLoader#openResource); if no SolrResourceLoader instance is provided, a default one
     * will be created.
     * </p>
     * <p>
     * Consider passing a non-null 'name' parameter in all use-cases since it is used for logging & exception reporting.
     * </p>
     * @param loader the resource loader used to obtain an input stream if 'is' is null
     * @param name the resource name used if the input stream 'is' is null
     * @param is the resource as a stream
     * @param prefix an optional prefix that will be preprended to all non-absolute xpath expressions
     * @throws javax.xml.parsers.ParserConfigurationException
     * @throws java.io.IOException
     * @throws org.xml.sax.SAXException
     * @deprecated Use {@link #Config(SolrResourceLoader, String, InputSource, String)} instead. 
     */
    @Deprecated
    public Config(SolrResourceLoader loader, String name, InputStream is, String prefix)
            throws ParserConfigurationException, IOException, SAXException {
        this(loader, name, (is == null) ? null : new InputSource(is), prefix);
    }

    /**
     * Builds a config:
     * <p>
     * Note that the 'name' parameter is used to obtain a valid input stream if no valid one is provided through 'is'.
     * If no valid stream is provided, a valid SolrResourceLoader instance should be provided through 'loader' so
     * the resource can be opened (@see SolrResourceLoader#openResource); if no SolrResourceLoader instance is provided, a default one
     * will be created.
     * </p>
     * <p>
     * Consider passing a non-null 'name' parameter in all use-cases since it is used for logging & exception reporting.
     * </p>
     * @param loader the resource loader used to obtain an input stream if 'is' is null
     * @param name the resource name used if the input stream 'is' is null
     * @param is the resource as a SAX InputSource
     * @param prefix an optional prefix that will be preprended to all non-absolute xpath expressions
     * @throws javax.xml.parsers.ParserConfigurationException
     * @throws java.io.IOException
     * @throws org.xml.sax.SAXException
     */
    public Config(SolrResourceLoader loader, String name, InputSource is, String prefix)
            throws ParserConfigurationException, IOException, SAXException {
        if (loader == null) {
            loader = new SolrResourceLoader(null);
        }
        this.loader = loader;
        this.name = name;
        this.prefix = (prefix != null && !prefix.endsWith("/")) ? prefix + '/' : prefix;
        try {
            javax.xml.parsers.DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            if (is == null) {
                is = new InputSource(loader.openConfig(name));
                is.setSystemId(SystemIdResolver.createSystemIdFromResourceName(name));
            }

            // only enable xinclude, if a SystemId is available
            if (is.getSystemId() != null) {
                try {
                    dbf.setXIncludeAware(true);
                    dbf.setNamespaceAware(true);
                } catch (UnsupportedOperationException e) {
                    log.warn(name + " XML parser doesn't support XInclude option");
                }
            }

            final DocumentBuilder db = dbf.newDocumentBuilder();
            db.setEntityResolver(new SystemIdResolver(loader));
            db.setErrorHandler(xmllog);
            try {
                doc = db.parse(is);
            } finally {
                // some XML parsers are broken and don't close the byte stream (but they should according to spec)
                IOUtils.closeQuietly(is.getByteStream());
            }

            DOMUtil.substituteProperties(doc, loader.getCoreProperties());
        } catch (ParserConfigurationException e) {
            SolrException.log(log, "Exception during parsing file: " + name, e);
            throw e;
        } catch (SAXException e) {
            SolrException.log(log, "Exception during parsing file: " + name, e);
            throw e;
        } catch (SolrException e) {
            SolrException.log(log, "Error in " + name, e);
            throw e;
        }
    }

    /**
     * @since solr 1.3
     */
    public SolrResourceLoader getResourceLoader() {
        return loader;
    }

    /**
     * @since solr 1.3
     */
    public String getResourceName() {
        return name;
    }

    public String getName() {
        return name;
    }

    public Document getDocument() {
        return doc;
    }

    public XPath getXPath() {
        return xpathFactory.newXPath();
    }

    private String normalize(String path) {
        return (prefix == null || path.startsWith("/")) ? path : prefix + path;
    }

    public Object evaluate(String path, QName type) {
        XPath xpath = xpathFactory.newXPath();
        try {
            String xstr = normalize(path);

            // TODO: instead of prepending /prefix/, we could do the search rooted at /prefix...
            Object o = xpath.evaluate(xstr, doc, type);
            return o;

        } catch (XPathExpressionException e) {
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error in xpath:" + path + " for " + name,
                    e, false);
        }
    }

    public Node getNode(String path, boolean errIfMissing) {
        XPath xpath = xpathFactory.newXPath();
        Node nd = null;
        String xstr = normalize(path);

        try {
            nd = (Node) xpath.evaluate(xstr, doc, XPathConstants.NODE);

            if (nd == null) {
                if (errIfMissing) {
                    throw new RuntimeException(name + " missing " + path);
                } else {
                    log.debug(name + " missing optional " + path);
                    return null;
                }
            }

            log.trace(name + ":" + path + "=" + nd);
            return nd;

        } catch (XPathExpressionException e) {
            SolrException.log(log, "Error in xpath", e);
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error in xpath:" + xstr + " for " + name,
                    e, false);
        } catch (SolrException e) {
            throw (e);
        } catch (Throwable e) {
            SolrException.log(log, "Error in xpath", e);
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error in xpath:" + xstr + " for " + name,
                    e, false);
        }
    }

    public String getVal(String path, boolean errIfMissing) {
        Node nd = getNode(path, errIfMissing);
        if (nd == null)
            return null;

        String txt = DOMUtil.getText(nd);

        log.debug(name + ' ' + path + '=' + txt);
        return txt;

        /******
        short typ = nd.getNodeType();
        if (typ==Node.ATTRIBUTE_NODE || typ==Node.TEXT_NODE) {
          return nd.getNodeValue();
        }
        return nd.getTextContent();
        ******/
    }

    public String get(String path) {
        return getVal(path, true);
    }

    public String get(String path, String def) {
        String val = getVal(path, false);
        return val != null ? val : def;
    }

    public int getInt(String path) {
        return Integer.parseInt(getVal(path, true));
    }

    public int getInt(String path, int def) {
        String val = getVal(path, false);
        return val != null ? Integer.parseInt(val) : def;
    }

    public boolean getBool(String path) {
        return Boolean.parseBoolean(getVal(path, true));
    }

    public boolean getBool(String path, boolean def) {
        String val = getVal(path, false);
        return val != null ? Boolean.parseBoolean(val) : def;
    }

    public float getFloat(String path) {
        return Float.parseFloat(getVal(path, true));
    }

    public float getFloat(String path, float def) {
        String val = getVal(path, false);
        return val != null ? Float.parseFloat(val) : def;
    }

    public double getDouble(String path) {
        return Double.parseDouble(getVal(path, true));
    }

    public double getDouble(String path, double def) {
        String val = getVal(path, false);
        return val != null ? Double.parseDouble(val) : def;
    }

    public Version getLuceneVersion(String path) {
        return parseLuceneVersionString(getVal(path, true));
    }

    public Version getLuceneVersion(String path, Version def) {
        String val = getVal(path, false);
        if (val == null) {
            if (!versionWarningAlreadyLogged.getAndSet(true)) {
                log.warn("the luceneMatchVersion is not specified, defaulting to " + def
                        + " emulation. You should at some point declare and reindex to at least 3.0, "
                        + "because 2.4 emulation is deprecated and will be removed in 4.0. "
                        + "This parameter will be mandatory in 4.0.");
            }
            return def;
        } else {
            return parseLuceneVersionString(val);
        }
    }

    private static final AtomicBoolean versionWarningAlreadyLogged = new AtomicBoolean(false);

    public static final Version parseLuceneVersionString(final String matchVersion) {
        String parsedMatchVersion = matchVersion.toUpperCase(Locale.ENGLISH);

        // be lenient with the supplied version parameter
        parsedMatchVersion = parsedMatchVersion.replaceFirst("^(\\d)\\.(\\d)$", "LUCENE_$1$2");

        final Version version;
        try {
            version = Version.valueOf(parsedMatchVersion);
        } catch (IllegalArgumentException iae) {
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                    "Invalid luceneMatchVersion '" + matchVersion + "', valid values are: "
                            + Arrays.toString(Version.values()) + " or a string in format 'V.V'",
                    iae, false);
        }

        if (version == Version.LUCENE_CURRENT && !versionWarningAlreadyLogged.getAndSet(true)) {
            log.warn("You should not use LUCENE_CURRENT as luceneMatchVersion property: "
                    + "if you use this setting, and then Solr upgrades to a newer release of Lucene, "
                    + "sizable changes may happen. If precise back compatibility is important "
                    + "then you should instead explicitly specify an actual Lucene version.");
        }

        return version;
    }

    // The following functions were moved to ResourceLoader
    //-----------------------------------------------------------------------------

    /**
     * @deprecated Use {@link SolrResourceLoader#getConfigDir()} instead.
     */
    @Deprecated
    public String getConfigDir() {
        return loader.getConfigDir();
    }

    /**
     * @deprecated Use {@link SolrResourceLoader#openResource(String)} instead.
     */
    @Deprecated
    public InputStream openResource(String resource) {
        return loader.openResource(resource);
    }

    /**
     * @deprecated Use {@link SolrResourceLoader#getLines(String)} instead.
     */
    @Deprecated
    public List<String> getLines(String resource) throws IOException {
        return loader.getLines(resource);
    }

    /**
     * @deprecated Use {@link SolrResourceLoader#findClass(String, String[])} instead.
     */
    @Deprecated
    public Class findClass(String cname, String... subpackages) {
        return loader.findClass(cname, subpackages);
    }

    /**
     * @deprecated Use {@link SolrResourceLoader#newInstance(String, String[])} instead.
     */
    @Deprecated
    public Object newInstance(String cname, String... subpackages) {
        return loader.newInstance(cname, subpackages);
    }

    /**
     * @deprecated Use {@link SolrResourceLoader#getInstanceDir()} instead.
     */
    @Deprecated
    public String getInstanceDir() {
        return loader.getInstanceDir();
    }
}