package com.constellio.data.dao.services.solr.serverFactories;
import static com.constellio.data.conf.HashingEncoding.BASE64;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import com.constellio.data.conf.HashingEncoding;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient.RemoteSolrException;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.constellio.data.io.IOServicesFactory;
import com.constellio.data.io.concurrent.filesystem.AtomicFileSystem;
import com.constellio.data.io.concurrent.filesystem.AtomicLocalFileSystem;
import com.constellio.data.io.concurrent.filesystem.ChildAtomicFileSystem;
public class HttpSolrServerFactory extends AbstractSolrServerFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpSolrServerFactory.class);
private List<AtomicFileSystem> atomicFileSystems = new ArrayList<>();
private List<SolrClient> solrClients = new ArrayList<>();
private final String url;
private IOServicesFactory ioServicesFactory;
public HttpSolrServerFactory(String url, IOServicesFactory ioServicesFactory) {
super();
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
this.url = url;
this.ioServicesFactory = ioServicesFactory;
}
@Override
public synchronized SolrClient newSolrServer(String core) {
SolrClient solrClient = getSolrClient(core);
solrClients.add(solrClient);
return solrClient;
}
@Override
public synchronized void clear() {
for (AtomicFileSystem atomicFileSystem : atomicFileSystems)
atomicFileSystem.close();
for (SolrClient solrClient : solrClients)
try {
solrClient.close();
} catch (IOException ioe) {
LOGGER.error("Error while closing solr client", ioe);
}
}
@Override
public synchronized AtomicFileSystem getConfigFileSystem(String core) {
try {
URL urlToSolrServer = new URL(url);
String host = urlToSolrServer.getHost();
if (!host.equals("localhost") && !host.equals("127.0.0.1")) {
LOGGER.warn("AtomicFileSystem does not support HTTP solr");
}
AtomicFileSystem fileSystem = getAtomicFileSystem(core);
atomicFileSystems.add(fileSystem);
return fileSystem;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
private String getRootFolder(String core)
throws SolrServerException, IOException {
if (core.isEmpty()) {
return getSolrServerLocation().getAbsolutePath();
} else {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(CommonParams.QT, "/admin/cores");
QueryResponse response;
try {
response = getAdminServer().query(params);
} catch (RemoteSolrException e) {
//This is a bug in Solr that sometime throw an exception if send a request to the server every time.
//https://issues.apache.org/jira/browse/SOLR-7785
try {
Thread.sleep(1000);
response = getAdminServer().query(params);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
}
SimpleOrderedMap<SimpleOrderedMap<String>> status = (SimpleOrderedMap<SimpleOrderedMap<String>>) response
.getResponse().get("status");
SimpleOrderedMap<String> coreInfo = status.get(core);
String instanceDir = coreInfo.get("instanceDir");
String baseDir = instanceDir + "conf";
return baseDir;
}
}
@Override
public synchronized AtomicFileSystem getConfigFileSystem() {
AtomicFileSystem atomicFileSystem = getAtomicFileSystem("");
atomicFileSystems.add(atomicFileSystem);
return atomicFileSystem;
}
private File getSolrServerLocation()
throws SolrServerException, IOException {
CoreAdminRequest coreAdminRequest = new CoreAdminRequest();
coreAdminRequest.setAction(CoreAdminAction.STATUS);
CoreAdminResponse process = coreAdminRequest.process(getAdminServer());
NamedList<NamedList<Object>> coreStatus = process.getCoreStatus();
File parent = null;
for (Entry<String, NamedList<Object>> aCoreStatus : coreStatus) {
File coreConfigFld = new File(aCoreStatus.getValue().get("instanceDir").toString());
File solrFld = coreConfigFld.getParentFile();
if (parent == null)
parent = solrFld;
else if (!parent.equals(solrFld))
throw new UnsupportedOperationException("TODO ?!");
}
return parent;
}
@Override
protected AtomicFileSystem getAtomicFileSystem(String core) {
try {
return new ChildAtomicFileSystem(new AtomicLocalFileSystem(ioServicesFactory.newHashingService(HashingEncoding.BASE64)), getRootFolder(core));
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void reloadSolrServer(String core) {
CoreAdminResponse adminResponse;
try {
adminResponse = CoreAdminRequest.reloadCore(core, getAdminServer());
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
adminResponse.getCoreStatus();
}
@Override
protected SolrClient getSolrClient(String core) {
return new HttpSolrClient(url + "/" + core);
}
}