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

Java tutorial

Introduction

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

Source

package org.apache.solr.core;

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

import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.util.DOMUtil;

import com.google.common.base.Function;
import com.google.common.base.Functions;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Locale;

/**
 *
 */
public class ConfigSolrXml extends ConfigSolr {

    protected static Logger log = LoggerFactory.getLogger(ConfigSolrXml.class);

    private final CoresLocator coresLocator;

    public ConfigSolrXml(Config config) {
        super(config);
        try {
            checkForIllegalConfig();
            fillPropMap();
            coresLocator = new CorePropertiesLocator(getCoreRootDirectory());
        } catch (IOException e) {
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
        }
    }

    private void checkForIllegalConfig() throws IOException {

        // Do sanity checks - we don't want to find old style config
        failIfFound("solr/@coreLoadThreads");
        failIfFound("solr/@persistent");
        failIfFound("solr/@sharedLib");
        failIfFound("solr/@zkHost");

        failIfFound("solr/logging/@class");
        failIfFound("solr/logging/@enabled");
        failIfFound("solr/logging/watcher/@size");
        failIfFound("solr/logging/watcher/@threshold");

        failIfFound("solr/cores/@adminHandler");
        failIfFound("solr/cores/@distribUpdateConnTimeout");
        failIfFound("solr/cores/@distribUpdateSoTimeout");
        failIfFound("solr/cores/@host");
        failIfFound("solr/cores/@hostContext");
        failIfFound("solr/cores/@hostPort");
        failIfFound("solr/cores/@leaderVoteWait");
        failIfFound("solr/cores/@leaderConflictResolveWait");
        failIfFound("solr/cores/@genericCoreNodeNames");
        failIfFound("solr/cores/@managementPath");
        failIfFound("solr/cores/@shareSchema");
        failIfFound("solr/cores/@transientCacheSize");
        failIfFound("solr/cores/@zkClientTimeout");

        // These have no counterpart in 5.0, asking for any of these in Solr 5.0
        // will result in an error being
        // thrown.
        failIfFound("solr/cores/@defaultCoreName");
        failIfFound("solr/@persistent");
        failIfFound("solr/cores/@adminPath");

    }

    private void failIfFound(String xPath) {

        if (config.getVal(xPath, false) != null) {
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                    "Should not have found " + xPath + " solr.xml may be a mix of old and new style formats.");
        }
    }

    private NamedList<Object> readNodeListAsNamedList(String path) {
        NodeList nodes = config.getNodeList(path, false);
        if (nodes != null) {
            NamedList<Object> namedList = DOMUtil.nodesToNamedList(nodes);
            return namedList;
        }
        return new NamedList<>();
    }

    private void fillPropMap() {
        NamedList<Object> unknownConfigParams = new NamedList<>();

        // shardHandlerFactory is parsed differently in the base class as a plugin, so we're excluding this node from the node list
        fillSolrSection(readNodeListAsNamedList("solr/*[@name][not(name()='shardHandlerFactory')]"));

        thereCanBeOnlyOne("solr/solrcloud", "<solrcloud>");
        fillSolrCloudSection(readNodeListAsNamedList("solr/solrcloud/*[@name]"));

        thereCanBeOnlyOne("solr/logging", "<logging>");
        thereCanBeOnlyOne("solr/logging/watcher", "Logging <watcher>");
        fillLoggingSection(readNodeListAsNamedList("solr/logging/*[@name]"),
                readNodeListAsNamedList("solr/logging/watcher/*[@name]"));
    }

    private void fillSolrSection(NamedList<Object> nl) {
        String s = "Main";
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_ADMINHANDLER, "adminHandler");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_COLLECTIONSHANDLER, "collectionsHandler");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_INFOHANDLER, "infoHandler");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_COREROOTDIRECTORY, "coreRootDirectory");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_MANAGEMENTPATH, "managementPath");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_SHAREDLIB, "sharedLib");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_CONFIGSETBASEDIR, "configSetBaseDir");

        storeConfigPropertyAsBoolean(s, nl, CfgProp.SOLR_SHARESCHEMA, "shareSchema");

        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_CORELOADTHREADS, "coreLoadThreads");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_TRANSIENTCACHESIZE, "transientCacheSize");

        errorOnLeftOvers(s, nl);
    }

    private void fillSolrCloudSection(NamedList<Object> nl) {

        String s = "<solrcloud>";
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_DISTRIBUPDATECONNTIMEOUT, "distribUpdateConnTimeout");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_DISTRIBUPDATESOTIMEOUT, "distribUpdateSoTimeout");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_MAXUPDATECONNECTIONS, "maxUpdateConnections");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_MAXUPDATECONNECTIONSPERHOST, "maxUpdateConnectionsPerHost");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_LEADERVOTEWAIT, "leaderVoteWait");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_LEADERCONFLICTRESOLVEWAIT, "leaderConflictResolveWait");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_ZKCLIENTTIMEOUT, "zkClientTimeout");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_AUTOREPLICAFAILOVERBADNODEEXPIRATION,
                "autoReplicaFailoverBadNodeExpiration");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_AUTOREPLICAFAILOVERWAITAFTEREXPIRATION,
                "autoReplicaFailoverWaitAfterExpiration");
        storeConfigPropertyAsInt(s, nl, CfgProp.SOLR_AUTOREPLICAFAILOVERWORKLOOPDELAY,
                "autoReplicaFailoverWorkLoopDelay");

        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_HOST, "host");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_HOSTCONTEXT, "hostContext");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_HOSTPORT, "hostPort");
        storeConfigPropertyAsString(s, nl, CfgProp.SOLR_ZKHOST, "zkHost");

        storeConfigPropertyAsBoolean(s, nl, CfgProp.SOLR_GENERICCORENODENAMES, "genericCoreNodeNames");

        errorOnLeftOvers(s, nl);
    }

    private void fillLoggingSection(NamedList<Object> loggingConfig, NamedList<Object> loggingWatcherConfig) {

        String s = "<logging>";
        storeConfigPropertyAsString(s, loggingConfig, CfgProp.SOLR_LOGGING_CLASS, "class");
        storeConfigPropertyAsBoolean(s, loggingConfig, CfgProp.SOLR_LOGGING_ENABLED, "enabled");

        errorOnLeftOvers(s, loggingConfig);

        s = "Logging <watcher>";
        storeConfigPropertyAsInt(s, loggingWatcherConfig, CfgProp.SOLR_LOGGING_WATCHER_SIZE, "size");
        storeConfigPropertyAsString(s, loggingWatcherConfig, CfgProp.SOLR_LOGGING_WATCHER_THRESHOLD, "threshold");

        errorOnLeftOvers(s, loggingWatcherConfig);
    }

    private <T> void storeConfigProperty(String section, NamedList<Object> config, CfgProp propertyKey, String name,
            Function<Object, T> valueTransformer, Class<T> clazz) {
        List<Object> values = config.removeAll(name);
        if (null != values && 0 != values.size()) {
            if (1 < values.size()) {
                throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                        String.format(Locale.ROOT,
                                "%s section of solr.xml contains duplicated '%s'" + " in solr.xml: %s", section,
                                name, values));
            } else {
                Object value = values.get(0);
                if (value != null) {
                    if (value.getClass().isAssignableFrom(clazz)) {
                        propMap.put(propertyKey, value);
                    } else {
                        propMap.put(propertyKey, valueTransformer.apply(value));
                    }
                } else {
                    propMap.put(propertyKey, null);
                }
            }
        }
    }

    private void storeConfigPropertyAsString(String section, NamedList<Object> config, CfgProp propertyKey,
            String name) {
        storeConfigProperty(section, config, propertyKey, name, Functions.toStringFunction(), String.class);
    }

    private void storeConfigPropertyAsInt(String section, NamedList<Object> config, CfgProp propertyKey,
            String xmlElementName) {
        storeConfigProperty(section, config, propertyKey, xmlElementName, TO_INT_FUNCTION, Integer.class);
    }

    private void storeConfigPropertyAsBoolean(String section, NamedList<Object> config, CfgProp propertyKey,
            String name) {
        storeConfigProperty(section, config, propertyKey, name, TO_BOOLEAN_FUNCTION, Boolean.class);
    }

    /** throws an error if more then one element matching the xpath */
    private void thereCanBeOnlyOne(String xpath, String section) {
        NodeList lst = config.getNodeList(xpath, false);
        if (1 < lst.getLength())
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                    lst.getLength() + " instances of " + section + " found in solr.xml");
    }

    /** logs each item in leftovers and then throws an exception with a summary */
    private void errorOnLeftOvers(String section, NamedList<Object> leftovers) {

        if (null == leftovers || 0 == leftovers.size())
            return;

        List<String> unknownElements = new ArrayList<String>(leftovers.size());
        for (Map.Entry<String, Object> unknownElement : leftovers) {
            log.error("Unknown config parameter in {} section of solr.xml: {} -> {}", section,
                    unknownElement.getKey(), unknownElement.getValue());
            unknownElements.add(unknownElement.getKey());
        }
        if (!unknownElements.isEmpty()) {
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                    String.format(Locale.ROOT, "%s section of solr.xml contains %d unknown config parameter(s): %s",
                            section, unknownElements.size(), unknownElements));
        }
    }

    @Override
    public String getDefaultCoreName() {
        return "collection1";
    }

    @Override
    public boolean isPersistent() {
        return true;
    }

    @Override
    protected String getShardHandlerFactoryConfigPath() {
        return "solr/shardHandlerFactory";
    }

    @Override
    public String getAdminPath() {
        return DEFAULT_CORE_ADMIN_PATH;
    }

    @Override
    public CoresLocator getCoresLocator() {
        return coresLocator;
    }

    private static final Function<Map.Entry<String, Object>, String> GET_KEY_FUNCTION = new Function<Map.Entry<String, Object>, String>() {
        @Override
        public String apply(Map.Entry<String, Object> input) {
            return input.getKey();
        }
    };

    private static final Function<Object, Integer> TO_INT_FUNCTION = new Function<Object, Integer>() {
        @Override
        public Integer apply(Object input) {
            try {
                return Integer.parseInt(String.valueOf(input));
            } catch (NumberFormatException exc) {
                throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                        String.format(Locale.ROOT, "Value of '%s' can not be parsed as 'int'", input));
            }
        }
    };

    private static final Function<Object, Boolean> TO_BOOLEAN_FUNCTION = new Function<Object, Boolean>() {
        @Override
        public Boolean apply(Object input) {
            if (input instanceof String) {
                return Boolean.valueOf(String.valueOf(input));
            }
            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
                    String.format(Locale.ROOT, "Value of '%s' can not be parsed as 'bool'", input));
        }
    };
}