blob: 523d6418a29352ec2c3ed91f79b15e881ce0f5c9 [file] [log] [blame]
/*
* 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.jackrabbit.oak.plugins.index.solr.server;
import java.io.File;
import java.io.IOException;
import javax.annotation.CheckForNull;
import org.apache.jackrabbit.oak.plugins.index.solr.configuration.RemoteSolrServerConfiguration;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.SolrPingResponse;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkStateReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* {@link org.apache.jackrabbit.oak.plugins.index.solr.server.SolrServerProvider} for remote Solr installations.
*/
public class RemoteSolrServerProvider implements SolrServerProvider {
private final Logger log = LoggerFactory.getLogger(RemoteSolrServerProvider.class);
private final RemoteSolrServerConfiguration remoteSolrServerConfiguration;
public RemoteSolrServerProvider(RemoteSolrServerConfiguration remoteSolrServerConfiguration) {
this.remoteSolrServerConfiguration = remoteSolrServerConfiguration;
}
@CheckForNull
@Override
public SolrServer getSolrServer() throws Exception {
SolrServer solrServer = null;
if (remoteSolrServerConfiguration.getSolrZkHost() != null && remoteSolrServerConfiguration.getSolrZkHost().length() > 0) {
try {
solrServer = initializeWithCloudSolrServer();
} catch (Exception e) {
log.warn("unable to initialize SolrCloud client for {}", remoteSolrServerConfiguration.getSolrZkHost(), e);
}
}
if (solrServer == null && remoteSolrServerConfiguration.getSolrHttpUrls() != null && remoteSolrServerConfiguration.getSolrHttpUrls().length == 1
&& remoteSolrServerConfiguration.getSolrHttpUrls()[0] != null && remoteSolrServerConfiguration.getSolrHttpUrls()[0].length() > 0) {
try {
solrServer = initializeWithExistingHttpServer();
} catch (Exception e1) {
log.warn("unable to initialize Solr HTTP client for {}", remoteSolrServerConfiguration.getSolrHttpUrls(), e1);
}
}
if (solrServer == null) {
throw new IOException("could not connect to any remote Solr server");
}
return solrServer;
}
@CheckForNull
@Override
public SolrServer getIndexingSolrServer() throws Exception {
SolrServer server = getSolrServer();
if (server instanceof HttpSolrServer) {
String url = ((HttpSolrServer) server).getBaseURL();
server = new ConcurrentUpdateSolrServer(url, 1000, Runtime.getRuntime().availableProcessors());
}
return server;
}
@CheckForNull
@Override
public SolrServer getSearchingSolrServer() throws Exception {
return getSolrServer();
}
private SolrServer initializeWithExistingHttpServer() throws IOException, SolrServerException {
// try basic Solr HTTP client
HttpSolrServer httpSolrServer = new HttpSolrServer(remoteSolrServerConfiguration.getSolrHttpUrls()[0]);
SolrPingResponse ping = httpSolrServer.ping();
if (ping != null && 0 == ping.getStatus()) {
return httpSolrServer;
} else {
throw new IOException("the found HTTP Solr server is not alive");
}
}
private SolrServer initializeWithCloudSolrServer() throws IOException {
// try SolrCloud client
CloudSolrServer cloudSolrServer = new CloudSolrServer(remoteSolrServerConfiguration.getSolrZkHost());
cloudSolrServer.setZkConnectTimeout(100);
if (connectToZK(cloudSolrServer)) {
cloudSolrServer.setDefaultCollection("collection1"); // workaround for first request when the needed collection may not exist
// create specified collection if it doesn't exists
try {
createCollectionIfNeeded(cloudSolrServer);
} catch (Throwable t) {
if (log.isWarnEnabled()) {
log.warn("could not create the collection on {}", remoteSolrServerConfiguration.getSolrZkHost(), t);
}
}
cloudSolrServer.setDefaultCollection(remoteSolrServerConfiguration.getSolrCollection());
// SolrCloud may need some time to sync on collection creation (to spread it over the shards / replicas)
int i = 0;
while (i < 3) {
try {
SolrPingResponse ping = cloudSolrServer.ping();
if (ping != null && 0 == ping.getStatus()) {
return cloudSolrServer;
} else {
throw new IOException("the found SolrCloud server is not alive");
}
} catch (Exception e) {
// wait a bit
try {
if (log.isDebugEnabled()) {
log.debug("server is not alive yet, wait a bit", e);
}
Thread.sleep(3000);
} catch (InterruptedException e1) {
// do nothing
}
}
i++;
}
throw new IOException("the found SolrCloud server is not alive");
} else {
throw new IOException("could not connect to Zookeeper hosted at " + remoteSolrServerConfiguration.getSolrZkHost());
}
}
private boolean connectToZK(CloudSolrServer cloudSolrServer) {
boolean connected = false;
for (int i = 0; i < 3; i++) {
try {
cloudSolrServer.connect();
connected = true;
break;
} catch (Exception e) {
log.warn("could not connect to ZK", e);
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// do nothing
}
}
}
return connected;
}
private void createCollectionIfNeeded(CloudSolrServer cloudSolrServer) throws SolrServerException {
String solrCollection = remoteSolrServerConfiguration.getSolrCollection();
try {
ZkStateReader zkStateReader = cloudSolrServer.getZkStateReader();
SolrZkClient zkClient = zkStateReader.getZkClient();
if (zkClient.isConnected() && !zkClient.exists("/configs/" + solrCollection, false)) {
String solrConfDir = remoteSolrServerConfiguration.getSolrConfDir();
File dir;
if (solrConfDir != null && solrConfDir.length() > 0) {
dir = new File(solrConfDir);
} else {
dir = new File(getClass().getResource("/solr/oak/conf").getFile());
}
ZkController.uploadConfigDir(zkClient, dir, solrCollection);
UpdateRequest req = new UpdateRequest("/admin/collections");
req.setParam("action", "CREATE");
req.setParam("numShards", String.valueOf(remoteSolrServerConfiguration.getSolrShardsNo()));
req.setParam("replicationFactor", String.valueOf(remoteSolrServerConfiguration.getSolrReplicationFactor()));
req.setParam("collection.configName", solrCollection);
req.setParam("name", solrCollection);
cloudSolrServer.request(req);
}
} catch (Exception e) {
log.warn("could not create collection {}", solrCollection);
throw new SolrServerException(e);
}
}
@Override
public void close() throws IOException {
// do nothing
}
}