You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yacy_search_server/source/net/yacy/cora/federate/solr/instance/EmbeddedInstance.java

253 lines
9.9 KiB

/**
* EmbeddedInstance
* Copyright 2013 by Michael Peter Christen
* First released 13.02.2013 at http://yacy.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program in the file lgpl21.txt
* If not, see <http://www.gnu.org/licenses/>.
*/
package net.yacy.cora.federate.solr.instance;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
import com.google.common.io.Files;
import net.yacy.cora.document.encoding.ASCII;
import net.yacy.cora.util.ConcurrentLog;
import net.yacy.kelondro.util.MemoryControl;
public class EmbeddedInstance implements SolrInstance {
private final static String[] confFiles = {"solrconfig.xml", "schema.xml", "stopwords.txt", "synonyms.txt", "protwords.txt", "currency.xml", "elevate.xml", "xslt/example.xsl", "xslt/json.xsl", "lang/"};
// additional a optional solrcore.properties (or solrcore.x86.properties for 32bit systems is copied
private CoreContainer coreContainer;
private final String defaultCoreName;
private final SolrCore defaultCore;
private final SolrClient defaultCoreServer;
private final File containerPath;
private final Map<String, SolrCore> cores;
private final Map<String, SolrClient> server;
public EmbeddedInstance(final File solr_config, final File containerPath, String givenDefaultCoreName, String[] initializeCoreNames) throws IOException {
super();
// copy the solrconfig.xml to the storage path
this.containerPath = containerPath;
// ensure that default core path exists
final File defaultCorePath = new File(containerPath, givenDefaultCoreName);
if (!defaultCorePath.exists()) defaultCorePath.mkdirs();
// migrate old conf directory
final File oldConf = new File(containerPath, "conf");
final File confDir = new File(defaultCorePath, "conf");
if (oldConf.exists()) oldConf.renameTo(confDir);
// migrate old data directory
final File oldData = new File(containerPath, "data");
final File dataDir = new File(defaultCorePath, "data");
if (oldData.exists()) oldData.renameTo(dataDir);
// create index subdirectory in data if it does not exist
final File indexDir = new File(dataDir, "index");
if (!indexDir.exists()) indexDir.mkdirs();
// initialize the cores' configuration
for (final String coreName: initializeCoreNames) {
initializeCoreConf(solr_config, containerPath, coreName);
}
// initialize the coreContainer
final File configFile = new File(solr_config, "solr.xml"); // the configuration file for all cores
this.coreContainer = CoreContainer.createAndLoad(containerPath.toPath(), configFile.toPath()); // this may take indefinitely long if solr files are broken
if (this.coreContainer == null) throw new IOException("cannot create core container dir = " + containerPath + ", configFile = " + configFile);
// get the default core from the coreContainer
this.defaultCoreName = givenDefaultCoreName;
ConcurrentLog.info("SolrEmbeddedInstance", "detected default solr core: " + this.defaultCoreName);
this.defaultCore = this.coreContainer.getCore(this.defaultCoreName);
assert givenDefaultCoreName.equals(this.defaultCore.getName()) : "givenDefaultCoreName = " + givenDefaultCoreName + ", this.defaultCore.getName() = " + this.defaultCore.getName();
if (this.defaultCore == null) {
throw new IOException("cannot get the default core; available = " + MemoryControl.available() + ", free = " + MemoryControl.free());
}
this.defaultCoreServer = new EmbeddedSolrServer(this.coreContainer, this.defaultCoreName);
// initialize core cache
this.cores = new ConcurrentHashMap<>();
this.cores.put(this.defaultCoreName, this.defaultCore);
this.server = new ConcurrentHashMap<>();
this.server.put(this.defaultCoreName, this.defaultCoreServer);
}
@Override
public int hashCode() {
return this.containerPath.hashCode();
}
@Override
public boolean equals(Object o) {
return o instanceof EmbeddedInstance && this.containerPath.equals(((EmbeddedInstance) o).containerPath);
}
private static void initializeCoreConf(final File solr_config, final File containerPath, String coreName) {
// ensure that default core path exists
final File corePath = new File(containerPath, coreName);
if (!corePath.exists()) corePath.mkdirs();
// check if core.properties exists in each path (thats new in Solr 5.0)
final File core_properties = new File(corePath, "core.properties");
if (!core_properties.exists()) {
// create the file
try (
/* Automatically closed by this try-with-resources statement */
FileOutputStream fos = new FileOutputStream(core_properties);
) {
fos.write(ASCII.getBytes("name=" + coreName + "\n"));
fos.write(ASCII.getBytes("shard=${shard:}\n"));
fos.write(ASCII.getBytes("collection=${collection:" + coreName + "}\n"));
fos.write(ASCII.getBytes("config=${solrconfig:solrconfig.xml}\n"));
fos.write(ASCII.getBytes("schema=${schema:schema.xml}\n"));
fos.write(ASCII.getBytes("coreNodeName=${coreNodeName:}\n"));
} catch (final IOException e) {
ConcurrentLog.logException(e);
}
}
// ensure necessary subpaths exist
final File conf = new File(corePath, "conf");
conf.mkdirs();
final File data = new File(corePath, "data");
data.mkdirs();
// (over-)write configuration into conf path
File source, target;
for (final String cf: confFiles) {
source = new File(solr_config, cf);
if (source.isDirectory()) {
target = new File(conf, cf);
target.mkdirs();
for (final String cfl: source.list()) {
try {
Files.copy(new File(source, cfl), new File(target, cfl));
} catch (final IOException e) {
e.printStackTrace();
}
}
} else {
target = new File(conf, cf);
target.getParentFile().mkdirs();
try {
Files.copy(source, target);
} catch (final IOException e) {
e.printStackTrace();
}
}
}
// copy the solrcore.properties
// for 32bit systems (os.arch name not containing '64') take the solrcore.x86.properties as solrcore.properties if exists
final String os = System.getProperty("os.arch");
if (os.contains("64")) {
source = new File(solr_config, "solrcore.properties");
} else {
source = new File(solr_config, "solrcore.x86.properties");
if (!source.exists()) {
source = new File(solr_config, "solrcore.properties");
}
}
// solr always reads the solrcore.properties file if exists in core/conf directory
target = new File(conf, "solrcore.properties");
if (source.exists()) {
try {
Files.copy(source, target);
ConcurrentLog.fine("initializeCoreConf", "overwrite " + target.getAbsolutePath() + " with " + source.getAbsolutePath());
} catch (final IOException ex) {
ex.printStackTrace();
}
}
}
public File getContainerPath() {
return this.containerPath;
}
public CoreContainer getCoreContainer() {
return this.coreContainer;
}
@Override
public String getDefaultCoreName() {
return this.defaultCoreName;
}
@Override
public Collection<String> getCoreNames() {
return this.coreContainer.getAllCoreNames();
}
@Override
public SolrClient getDefaultServer() {
return this.defaultCoreServer;
}
@Override
public SolrClient getServer(String coreName) {
SolrClient s = this.server.get(coreName);
if (s != null) return s;
s = new EmbeddedSolrServer(this.coreContainer, coreName);
this.server.put(coreName, s);
return s;
}
public SolrCore getDefaultCore() {
return this.defaultCore;
}
public SolrCore getCore(String name) {
SolrCore c = this.cores.get(name);
if (c != null) return c;
c = this.coreContainer.getCore(name);
this.cores.put(name, c);
return c;
}
@Override
protected void finalize() throws Throwable {
this.close();
}
@Override
public synchronized void close() {
for (final SolrCore core: this.cores.values()) core.close();
if (this.coreContainer != null) try {
this.coreContainer.shutdown();
this.coreContainer = null;
} catch (final Throwable e) {ConcurrentLog.logException(e);}
}
}