Java tutorial
/** * 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 java.io.*; import java.nio.channels.FileChannel; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeoutException; import java.text.SimpleDateFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import org.apache.solr.cloud.CloudDescriptor; import org.apache.solr.cloud.SolrZkServer; import org.apache.solr.cloud.ZkController; import org.apache.solr.cloud.ZkSolrResourceLoader; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.ZooKeeperException; import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.util.DOMUtil; import org.apache.solr.common.util.XML; import org.apache.solr.common.util.FileUtils; import org.apache.solr.handler.admin.CoreAdminHandler; import org.apache.solr.schema.IndexSchema; import org.apache.zookeeper.KeeperException; import org.apache.commons.io.IOUtils; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * @version $Id: CoreContainer.java 1054157 2010-12-31 18:36:14Z yonik $ * @since solr 1.3 */ public class CoreContainer { private static final String DEFAULT_DEFAULT_CORE_NAME = "collection1"; protected static Logger log = LoggerFactory.getLogger(CoreContainer.class); protected final Map<String, SolrCore> cores = new LinkedHashMap<String, SolrCore>(); protected boolean persistent = false; protected String adminPath = null; protected String managementPath = null; protected String hostPort; protected String hostContext; protected String host; protected CoreAdminHandler coreAdminHandler = null; protected File configFile = null; protected String libDir = null; protected ClassLoader libLoader = null; protected SolrResourceLoader loader = null; protected Properties containerProperties; protected Map<String, IndexSchema> indexSchemaCache; protected String adminHandler; protected boolean shareSchema; protected String solrHome; protected String defaultCoreName = ""; private ZkController zkController; private SolrZkServer zkServer; private String zkHost; { log.info("New CoreContainer " + System.identityHashCode(this)); } public CoreContainer() { solrHome = SolrResourceLoader.locateSolrHome(); } /** * Initalize CoreContainer directly from the constructor * * @param dir * @param configFile * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public CoreContainer(String dir, File configFile) throws ParserConfigurationException, IOException, SAXException { this.load(dir, configFile); } /** * Minimal CoreContainer constructor. * @param loader the CoreContainer resource loader */ public CoreContainer(SolrResourceLoader loader) { this.loader = loader; this.solrHome = loader.getInstanceDir(); } public CoreContainer(String solrHome) { this.solrHome = solrHome; } protected void initZooKeeper(String zkHost, int zkClientTimeout) { // if zkHost sys property is not set, we are not using ZooKeeper String zookeeperHost; if (zkHost == null) { zookeeperHost = System.getProperty("zkHost"); } else { zookeeperHost = zkHost; } String zkRun = System.getProperty("zkRun"); if (zkRun == null && zookeeperHost == null) return; // not in zk mode zkServer = new SolrZkServer(zkRun, zookeeperHost, solrHome, hostPort); zkServer.parseConfig(); zkServer.start(); // set client from server config if not already set if (zookeeperHost == null) { zookeeperHost = zkServer.getClientString(); } int zkClientConnectTimeout = 5000; if (zookeeperHost != null) { // we are ZooKeeper enabled try { // If this is an ensemble, allow for a long connect time for other servers to come up if (zkRun != null && zkServer.getServers().size() > 1) { zkClientConnectTimeout = 24 * 60 * 60 * 1000; // 1 day for embedded ensemble log.info("Zookeeper client=" + zookeeperHost + " Waiting for a quorum."); } else { log.info("Zookeeper client=" + zookeeperHost); } zkController = new ZkController(zookeeperHost, zkClientTimeout, zkClientConnectTimeout, host, hostPort, hostContext); String confDir = System.getProperty("bootstrap_confdir"); if (confDir != null) { File dir = new File(confDir); if (!dir.isDirectory()) { throw new IllegalArgumentException( "bootstrap_confdir must be a directory of configuration files"); } String confName = System.getProperty( ZkController.COLLECTION_PARAM_PREFIX + ZkController.CONFIGNAME_PROP, "configuration1"); zkController.uploadConfigDir(dir, confName); } } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (TimeoutException e) { log.error("Could not connect to ZooKeeper", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (IOException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (KeeperException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } } } public Properties getContainerProperties() { return containerProperties; } // Helper class to initialize the CoreContainer public static class Initializer { protected String solrConfigFilename = null; protected String dataDir = null; // override datadir for single core mode /** * @deprecated all cores now abort on configuration error regardless of configuration */ @Deprecated public boolean isAbortOnConfigurationError() { return true; } /** * @exception generates an error if you attempt to set this value to false * @deprecated all cores now abort on configuration error regardless of configuration */ @Deprecated public void setAbortOnConfigurationError(boolean abortOnConfigurationError) { if (false == abortOnConfigurationError) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Setting abortOnConfigurationError==false is no longer supported"); } // core container instantiation public CoreContainer initialize() throws IOException, ParserConfigurationException, SAXException { CoreContainer cores = null; String solrHome = SolrResourceLoader.locateSolrHome(); // TODO : fix broken logic confusing solr.xml with solrconfig.xml File fconf = new File(solrHome, solrConfigFilename == null ? "solr.xml" : solrConfigFilename); log.info("looking for solr.xml: " + fconf.getAbsolutePath()); cores = new CoreContainer(); if (fconf.exists()) { cores.load(solrHome, fconf); } else { log.info("no solr.xml file found - using default"); cores.load(solrHome, new ByteArrayInputStream(DEF_SOLR_XML.getBytes())); cores.configFile = fconf; } solrConfigFilename = cores.getConfigFile().getName(); return cores; } } private static Properties getCoreProps(String instanceDir, String file, Properties defaults) { if (file == null) file = "conf" + File.separator + "solrcore.properties"; File corePropsFile = new File(file); if (!corePropsFile.isAbsolute()) { corePropsFile = new File(instanceDir, file); } Properties p = defaults; if (corePropsFile.exists() && corePropsFile.isFile()) { p = new Properties(defaults); InputStream is = null; try { is = new FileInputStream(corePropsFile); p.load(is); } catch (IOException e) { log.warn("Error loading properties ", e); } finally { IOUtils.closeQuietly(is); } } return p; } //------------------------------------------------------------------- // Initialization / Cleanup //------------------------------------------------------------------- /** * Load a config file listing the available solr cores. * @param dir the home directory of all resources. * @param configFile the configuration file * @throws javax.xml.parsers.ParserConfigurationException * @throws java.io.IOException * @throws org.xml.sax.SAXException */ public void load(String dir, File configFile) throws ParserConfigurationException, IOException, SAXException { this.configFile = configFile; this.load(dir, new FileInputStream(configFile)); } /** * Load a config file listing the available solr cores. * * @param dir the home directory of all resources. * @param cfgis the configuration file InputStream * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public void load(String dir, InputStream cfgis) throws ParserConfigurationException, IOException, SAXException { this.loader = new SolrResourceLoader(dir); solrHome = loader.getInstanceDir(); try { Config cfg = new Config(loader, null, cfgis, null); String dcoreName = cfg.get("solr/cores/@defaultCoreName", null); if (dcoreName != null) { defaultCoreName = dcoreName; } persistent = cfg.getBool("solr/@persistent", false); libDir = cfg.get("solr/@sharedLib", null); zkHost = cfg.get("solr/@zkHost", null); adminPath = cfg.get("solr/cores/@adminPath", null); shareSchema = cfg.getBool("solr/cores/@shareSchema", false); int zkClientTimeout = cfg.getInt("solr/cores/@zkClientTimeout", 10000); hostPort = System.getProperty("hostPort"); if (hostPort == null) { hostPort = cfg.get("solr/cores/@hostPort", "8983"); } hostContext = cfg.get("solr/cores/@hostContext", "solr"); host = cfg.get("solr/cores/@host", null); if (shareSchema) { indexSchemaCache = new ConcurrentHashMap<String, IndexSchema>(); } adminHandler = cfg.get("solr/cores/@adminHandler", null); managementPath = cfg.get("solr/cores/@managementPath", null); zkClientTimeout = Integer .parseInt(System.getProperty("zkClientTimeout", Integer.toString(zkClientTimeout))); initZooKeeper(zkHost, zkClientTimeout); if (libDir != null) { File f = FileUtils.resolvePath(new File(dir), libDir); log.info("loading shared library: " + f.getAbsolutePath()); libLoader = SolrResourceLoader.createClassLoader(f, null); } if (adminPath != null) { if (adminHandler == null) { coreAdminHandler = new CoreAdminHandler(this); } else { coreAdminHandler = this.createMultiCoreHandler(adminHandler); } } 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); boolean defaultCoreFound = false; for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); try { String name = DOMUtil.getAttr(node, "name", null); if (null == name) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Each core in solr.xml must have a 'name'"); } if (name.equals(defaultCoreName)) { // for the default core we use a blank name, // later on attempts to access it by it's full name will // be mapped to this. name = ""; } CoreDescriptor p = new CoreDescriptor(this, name, DOMUtil.getAttr(node, "instanceDir", null)); // deal with optional settings String opt = DOMUtil.getAttr(node, "config", null); if (opt != null) { p.setConfigName(opt); } opt = DOMUtil.getAttr(node, "schema", null); if (opt != null) { p.setSchemaName(opt); } if (zkController != null) { opt = DOMUtil.getAttr(node, "shard", null); if (opt != null && opt.length() > 0) { p.getCloudDescriptor().setShardId(opt); } opt = DOMUtil.getAttr(node, "collection", null); if (opt != null) { p.getCloudDescriptor().setCollectionName(opt); } } opt = DOMUtil.getAttr(node, "properties", null); if (opt != null) { p.setPropertiesName(opt); } opt = DOMUtil.getAttr(node, CoreAdminParams.DATA_DIR, null); if (opt != null) { p.setDataDir(opt); } p.setCoreProperties(readProperties(cfg, node)); SolrCore core = create(p); register(name, core, false); } catch (Throwable ex) { SolrConfig.severeErrors.add(ex); SolrException.logOnce(log, null, ex); } } } finally { if (cfgis != null) { try { cfgis.close(); } catch (Exception xany) { } } } if (zkController != null) { try { synchronized (zkController.getZkStateReader().getUpdateLock()) { zkController.getZkStateReader().makeShardZkNodeWatches(false); zkController.getZkStateReader().updateCloudState(true); } } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (KeeperException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (IOException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } } } 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; } private boolean isShutDown = false; /** * Stops all cores. */ public void shutdown() { log.info("Shutting down CoreContainer instance=" + System.identityHashCode(this)); synchronized (cores) { try { for (SolrCore core : cores.values()) { core.close(); } cores.clear(); } finally { if (zkController != null) { zkController.close(); } if (zkServer != null) { zkServer.stop(); } isShutDown = true; } } } @Override protected void finalize() throws Throwable { try { if (!isShutDown) { log.error( "CoreContainer was not shutdown prior to finalize(), indicates a bug -- POSSIBLE RESOURCE LEAK!!! instance=" + System.identityHashCode(this)); shutdown(); } } finally { super.finalize(); } } /** * Registers a SolrCore descriptor in the registry using the specified name. * If returnPrevNotClosed==false, the old core, if different, is closed. if true, it is returned w/o closing the core * * @return a previous core having the same name if it existed */ public SolrCore register(String name, SolrCore core, boolean returnPrevNotClosed) { if (core == null) { throw new RuntimeException("Can not register a null core."); } if (name == null || name.indexOf('/') >= 0 || name.indexOf('\\') >= 0) { throw new RuntimeException("Invalid core name: " + name); } SolrCore old = null; synchronized (cores) { old = cores.put(name, core); core.setName(name); } if (zkController != null) { try { zkController.register(core.getName(), core.getCoreDescriptor().getCloudDescriptor(), true); } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (KeeperException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (IOException e) { log.error("", e); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "", e); } } if (old == null || old == core) { log.info("registering core: " + name); return null; } else { log.info("replacing core: " + name); if (!returnPrevNotClosed) { old.close(); } return old; } } /** * Registers a SolrCore descriptor in the registry using the core's name. * If returnPrev==false, the old core, if different, is closed. * @return a previous core having the same name if it existed and returnPrev==true */ public SolrCore register(SolrCore core, boolean returnPrev) { return register(core.getName(), core, returnPrev); } /** * Creates a new core based on a descriptor but does not register it. * * @param dcore a core descriptor * @return the newly created core * @throws javax.xml.parsers.ParserConfigurationException * @throws java.io.IOException * @throws org.xml.sax.SAXException */ public SolrCore create(CoreDescriptor dcore) throws ParserConfigurationException, IOException, SAXException { // Make the instanceDir relative to the cores instanceDir if not absolute File idir = new File(dcore.getInstanceDir()); if (!idir.isAbsolute()) { idir = new File(solrHome, dcore.getInstanceDir()); } String instanceDir = idir.getPath(); // Initialize the solr config SolrResourceLoader solrLoader = null; SolrConfig config = null; String zkConfigName = null; if (zkController == null) { solrLoader = new SolrResourceLoader(instanceDir, libLoader, getCoreProps(instanceDir, dcore.getPropertiesName(), dcore.getCoreProperties())); config = new SolrConfig(solrLoader, dcore.getConfigName(), null); } else { try { String collection = dcore.getCloudDescriptor().getCollectionName(); zkController.createCollectionZkNode(dcore.getCloudDescriptor()); // zkController.createCollectionZkNode(collection); zkConfigName = zkController.readConfigName(collection); if (zkConfigName == null) { log.error("Could not find config name for collection:" + collection); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "Could not find config name for collection:" + collection); } solrLoader = new ZkSolrResourceLoader(instanceDir, zkConfigName, libLoader, getCoreProps(instanceDir, dcore.getPropertiesName(), dcore.getCoreProperties()), zkController); config = getSolrConfigFromZk(zkConfigName, dcore.getConfigName(), solrLoader); } catch (KeeperException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } } IndexSchema schema = null; if (indexSchemaCache != null) { if (zkController != null) { File schemaFile = new File(dcore.getSchemaName()); if (!schemaFile.isAbsolute()) { schemaFile = new File( solrLoader.getInstanceDir() + "conf" + File.separator + dcore.getSchemaName()); } if (schemaFile.exists()) { String key = schemaFile.getAbsolutePath() + ":" + new SimpleDateFormat("yyyyMMddHHmmss", Locale.US) .format(new Date(schemaFile.lastModified())); schema = indexSchemaCache.get(key); if (schema == null) { log.info("creating new schema object for core: " + dcore.name); schema = new IndexSchema(config, dcore.getSchemaName(), null); indexSchemaCache.put(key, schema); } else { log.info("re-using schema object for core: " + dcore.name); } } } else { // TODO: handle caching from ZooKeeper - perhaps using ZooKeepers versioning // Don't like this cache though - how does it empty as last modified changes? } } if (schema == null) { if (zkController != null) { try { schema = getSchemaFromZk(zkConfigName, dcore.getSchemaName(), config, solrLoader); } catch (KeeperException e) { log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } catch (InterruptedException e) { // Restore the interrupted status Thread.currentThread().interrupt(); log.error("", e); throw new ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR, "", e); } } else { schema = new IndexSchema(config, dcore.getSchemaName(), null); } } String dataDir = null; SolrCore core = new SolrCore(dcore.getName(), dataDir, config, schema, dcore); return core; } /** * @return a Collection of registered SolrCores */ public Collection<SolrCore> getCores() { List<SolrCore> lst = new ArrayList<SolrCore>(); synchronized (cores) { lst.addAll(this.cores.values()); } return lst; } /** * @return a Collection of the names that cores are mapped to */ public Collection<String> getCoreNames() { List<String> lst = new ArrayList<String>(); synchronized (cores) { lst.addAll(this.cores.keySet()); } return lst; } /** This method is currently experimental. * @return a Collection of the names that a specific core is mapped to. */ public Collection<String> getCoreNames(SolrCore core) { List<String> lst = new ArrayList<String>(); synchronized (cores) { for (Map.Entry<String, SolrCore> entry : cores.entrySet()) { if (core == entry.getValue()) { lst.add(entry.getKey()); } } } return lst; } // ---------------- Core name related methods --------------- /** * Recreates a SolrCore. * While the new core is loading, requests will continue to be dispatched to * and processed by the old core * * @param name the name of the SolrCore to reload * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public void reload(String name) throws ParserConfigurationException, IOException, SAXException { name = checkDefault(name); SolrCore core; synchronized (cores) { core = cores.get(name); } if (core == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name); SolrCore newCore = create(core.getCoreDescriptor()); register(name, newCore, false); } private String checkDefault(String name) { return name.length() == 0 || defaultCoreName.equals(name) || name.trim().length() == 0 ? "" : name; } /** * Swaps two SolrCore descriptors. * @param n0 * @param n1 */ public void swap(String n0, String n1) { if (n0 == null || n1 == null) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Can not swap unnamed cores."); } n0 = checkDefault(n0); n1 = checkDefault(n1); synchronized (cores) { SolrCore c0 = cores.get(n0); SolrCore c1 = cores.get(n1); if (c0 == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n0); if (c1 == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n1); cores.put(n0, c1); cores.put(n1, c0); c0.setName(n1); c0.getCoreDescriptor().name = n1; c1.setName(n0); c1.getCoreDescriptor().name = n0; } log.info("swaped: " + n0 + " with " + n1); } /** Removes and returns registered core w/o decrementing it's reference count */ public SolrCore remove(String name) { name = checkDefault(name); synchronized (cores) { return cores.remove(name); } } /** Gets a core by name and increase its refcount. * @see SolrCore#open() * @see SolrCore#close() * @param name the core name * @return the core if found */ public SolrCore getCore(String name) { name = checkDefault(name); synchronized (cores) { SolrCore core = cores.get(name); if (core != null) core.open(); // increment the ref count while still synchronized return core; } } // ---------------- Multicore self related methods --------------- /** * Creates a CoreAdminHandler for this MultiCore. * @return a CoreAdminHandler */ protected CoreAdminHandler createMultiCoreHandler(final String adminHandlerClass) { SolrResourceLoader loader = new SolrResourceLoader(null, libLoader, null); Object obj = loader.newAdminHandlerInstance(CoreContainer.this, adminHandlerClass); if (!(obj instanceof CoreAdminHandler)) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "adminHandlerClass is not of type " + CoreAdminHandler.class); } return (CoreAdminHandler) obj; } public CoreAdminHandler getMultiCoreHandler() { return coreAdminHandler; } public String getDefaultCoreName() { return defaultCoreName; } // all of the following properties aren't synchronized // but this should be OK since they normally won't be changed rapidly public boolean isPersistent() { return persistent; } public void setPersistent(boolean persistent) { this.persistent = persistent; } public String getAdminPath() { return adminPath; } public void setAdminPath(String adminPath) { this.adminPath = adminPath; } public String getManagementPath() { return managementPath; } /** * Sets the alternate path for multicore handling: * This is used in case there is a registered unnamed core (aka name is "") to * declare an alternate way of accessing named cores. * This can also be used in a pseudo single-core environment so admins can prepare * a new version before swapping. * @param path */ public void setManagementPath(String path) { this.managementPath = path; } public File getConfigFile() { return configFile; } /** Persists the cores config file in cores.xml. */ public void persist() { persistFile(null); } /** Persists the cores config file in a user provided file. */ public void persistFile(File file) { log.info("Persisting cores config to " + (file == null ? configFile : file)); File tmpFile = null; try { // write in temp first if (file == null) { file = tmpFile = File.createTempFile("solr", ".xml", configFile.getParentFile()); } java.io.FileOutputStream out = new java.io.FileOutputStream(file); Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8")); persist(writer); writer.flush(); writer.close(); out.close(); // rename over origin or copy it this fails if (tmpFile != null) { if (tmpFile.renameTo(configFile)) tmpFile = null; else fileCopy(tmpFile, configFile); } } catch (java.io.FileNotFoundException xnf) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, xnf); } catch (java.io.IOException xio) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, xio); } finally { if (tmpFile != null) { if (!tmpFile.delete()) tmpFile.deleteOnExit(); } } } /** Write the cores configuration through a writer.*/ void persist(Writer w) throws IOException { w.write("<?xml version='1.0' encoding='UTF-8'?>"); w.write("<solr"); if (this.libDir != null) { writeAttribute(w, "sharedLib", libDir); } writeAttribute(w, "persistent", isPersistent()); w.write(">\n"); if (containerProperties != null && !containerProperties.isEmpty()) { writeProperties(w, containerProperties); } w.write("<cores"); writeAttribute(w, "adminPath", adminPath); if (adminHandler != null) writeAttribute(w, "adminHandler", adminHandler); if (shareSchema) writeAttribute(w, "shareSchema", "true"); if (!defaultCoreName.equals("")) writeAttribute(w, "defaultCoreName", defaultCoreName); w.write(">\n"); synchronized (cores) { for (SolrCore solrCore : cores.values()) { persist(w, solrCore.getCoreDescriptor()); } } w.write("</cores>\n"); w.write("</solr>\n"); } private void writeAttribute(Writer w, String name, Object value) throws IOException { if (value == null) return; w.write(" "); w.write(name); w.write("=\""); XML.escapeAttributeValue(value.toString(), w); w.write("\""); } /** Writes the cores configuration node for a given core. */ void persist(Writer w, CoreDescriptor dcore) throws IOException { w.write(" <core"); writeAttribute(w, "name", dcore.name); writeAttribute(w, "instanceDir", dcore.getInstanceDir()); //write config (if not default) String opt = dcore.getConfigName(); if (opt != null && !opt.equals(dcore.getDefaultConfigName())) { writeAttribute(w, "config", opt); } //write schema (if not default) opt = dcore.getSchemaName(); if (opt != null && !opt.equals(dcore.getDefaultSchemaName())) { writeAttribute(w, "schema", opt); } opt = dcore.getPropertiesName(); if (opt != null) { writeAttribute(w, "properties", opt); } opt = dcore.dataDir; if (opt != null) writeAttribute(w, "dataDir", opt); CloudDescriptor cd = dcore.getCloudDescriptor(); if (cd != null) { opt = cd.getShardId(); if (opt != null) writeAttribute(w, "shard", opt); // only write out the collection name if it's not the default (the core name) opt = cd.getCollectionName(); if (opt != null && !opt.equals(dcore.name)) writeAttribute(w, "collection", opt); } if (dcore.getCoreProperties() == null || dcore.getCoreProperties().isEmpty()) w.write("/>\n"); // core else { w.write(">\n"); writeProperties(w, dcore.getCoreProperties()); w.write("</core>"); } } private void writeProperties(Writer w, Properties props) throws IOException { for (Map.Entry<Object, Object> entry : props.entrySet()) { w.write("<property"); writeAttribute(w, "name", entry.getKey()); writeAttribute(w, "value", entry.getValue()); w.write("/>\n"); } } /** Copies a src file to a dest file: * used to circumvent the platform discrepancies regarding renaming files. */ public static void fileCopy(File src, File dest) throws IOException { IOException xforward = null; FileInputStream fis = null; FileOutputStream fos = null; FileChannel fcin = null; FileChannel fcout = null; try { fis = new FileInputStream(src); fos = new FileOutputStream(dest); fcin = fis.getChannel(); fcout = fos.getChannel(); // do the file copy 32Mb at a time final int MB32 = 32 * 1024 * 1024; long size = fcin.size(); long position = 0; while (position < size) { position += fcin.transferTo(position, MB32, fcout); } } catch (IOException xio) { xforward = xio; } finally { if (fis != null) try { fis.close(); fis = null; } catch (IOException xio) { } if (fos != null) try { fos.close(); fos = null; } catch (IOException xio) { } if (fcin != null && fcin.isOpen()) try { fcin.close(); fcin = null; } catch (IOException xio) { } if (fcout != null && fcout.isOpen()) try { fcout.close(); fcout = null; } catch (IOException xio) { } } if (xforward != null) { throw xforward; } } public String getSolrHome() { return solrHome; } public boolean isZooKeeperAware() { return zkController != null; } public ZkController getZkController() { return zkController; } private SolrConfig getSolrConfigFromZk(String zkConfigName, String solrConfigFileName, SolrResourceLoader resourceLoader) throws IOException, ParserConfigurationException, SAXException, KeeperException, InterruptedException { byte[] config = zkController.getConfigFileData(zkConfigName, solrConfigFileName); InputStream is = new ByteArrayInputStream(config); SolrConfig cfg = solrConfigFileName == null ? new SolrConfig(resourceLoader, SolrConfig.DEFAULT_CONF_FILE, is) : new SolrConfig(resourceLoader, solrConfigFileName, is); return cfg; } private IndexSchema getSchemaFromZk(String zkConfigName, String schemaName, SolrConfig config, SolrResourceLoader resourceLoader) throws KeeperException, InterruptedException { byte[] configBytes = zkController.getConfigFileData(zkConfigName, schemaName); InputStream is = new ByteArrayInputStream(configBytes); IndexSchema schema = new IndexSchema(config, schemaName, is); return schema; } private static final String DEF_SOLR_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<solr persistent=\"false\">\n" + " <cores adminPath=\"/admin/cores\" defaultCoreName=\"" + DEFAULT_DEFAULT_CORE_NAME + "\">\n" + " <core name=\"" + DEFAULT_DEFAULT_CORE_NAME + "\" instanceDir=\".\" />\n" + " </cores>\n" + "</solr>"; }