Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.client.solrj.impl;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Phaser;
import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpStatus;
import org.apache.http.entity.ContentType;
import org.apache.solr.client.solrj.ResponseParser;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.V2RequestSupport;
import org.apache.solr.client.solrj.embedded.SSLConfig;
import org.apache.solr.client.solrj.request.RequestWriter;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.client.solrj.util.Constants;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.StringUtils;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.params.UpdateParams;
import org.apache.solr.common.util.Base64;
import org.apache.solr.common.util.ContentStream;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.ObjectReleaseTracker;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.common.util.Utils;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.ProtocolHandlers;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.client.util.BytesContentProvider;
import org.eclipse.jetty.client.util.FormContentProvider;
import org.eclipse.jetty.client.util.InputStreamContentProvider;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.client.util.MultiPartContentProvider;
import org.eclipse.jetty.client.util.OutputStreamContentProvider;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.client.solrj.impl.BaseHttpSolrClient.RemoteExecutionException;
import static org.apache.solr.client.solrj.impl.BaseHttpSolrClient.RemoteSolrException;
import static org.apache.solr.common.util.Utils.getObjectByPath;
/**
* Difference between this {@link Http2SolrClient} and {@link HttpSolrClient}:
*
*
{@link Http2SolrClient} sends requests in HTTP/2
*
{@link Http2SolrClient} can point to multiple urls
*
{@link Http2SolrClient} does not expose its internal httpClient like {@link HttpSolrClient#getHttpClient()},
* sharing connection pools should be done by {@link Http2SolrClient.Builder#withHttpClient(Http2SolrClient)}
*
* @lucene.experimental
*/
public class Http2SolrClient extends SolrClient {
public static final String REQ_PRINCIPAL_KEY = "solr-req-principal";
private static volatile SSLConfig defaultSSLConfig;
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final String AGENT = "Solr[" + Http2SolrClient.class.getName() + "] 2.0";
private static final Charset FALLBACK_CHARSET = StandardCharsets.UTF_8;
private static final String DEFAULT_PATH = "/select";
private static final List errPath = Arrays.asList("metadata", "error-class");
private HttpClient httpClient;
private volatile Set queryParams = Collections.emptySet();
private int idleTimeout;
private ResponseParser parser = new BinaryResponseParser();
private volatile RequestWriter requestWriter = new BinaryRequestWriter();
private List listenerFactory = new LinkedList<>();
private AsyncTracker asyncTracker = new AsyncTracker();
/**
* The URL of the Solr server.
*/
private String serverBaseUrl;
private boolean closeClient;
private final String basicAuthAuthorizationStr;
protected Http2SolrClient(String serverBaseUrl, Builder builder) {
if (serverBaseUrl != null) {
if (!serverBaseUrl.equals("/") && serverBaseUrl.endsWith("/")) {
serverBaseUrl = serverBaseUrl.substring(0, serverBaseUrl.length() - 1);
}
if (serverBaseUrl.startsWith("//")) {
serverBaseUrl = serverBaseUrl.substring(1, serverBaseUrl.length());
}
this.serverBaseUrl = serverBaseUrl;
}
if (builder.idleTimeout != null && builder.idleTimeout > 0) idleTimeout = builder.idleTimeout;
else idleTimeout = HttpClientUtil.DEFAULT_SO_TIMEOUT;
if (builder.http2SolrClient == null) {
httpClient = createHttpClient(builder);
closeClient = true;
} else {
httpClient = builder.http2SolrClient.httpClient;
}
if (builder.basicAuthUser != null && builder.basicAuthPassword != null) {
basicAuthAuthorizationStr = basicAuthCredentialsToAuthorizationString(builder.basicAuthUser, builder.basicAuthPassword);
} else {
basicAuthAuthorizationStr = null;
}
assert ObjectReleaseTracker.track(this);
}
public void addListenerFactory(HttpListenerFactory factory) {
this.listenerFactory.add(factory);
}
// internal usage only
HttpClient getHttpClient() {
return httpClient;
}
// internal usage only
ProtocolHandlers getProtocolHandlers() {
return httpClient.getProtocolHandlers();
}
private HttpClient createHttpClient(Builder builder) {
HttpClient httpClient;
BlockingArrayQueue queue = new BlockingArrayQueue<>(256, 256);
ThreadPoolExecutor httpClientExecutor = new ExecutorUtil.MDCAwareThreadPoolExecutor(32,
256, 60, TimeUnit.SECONDS, queue, new SolrNamedThreadFactory("h2sc"));
SslContextFactory.Client sslContextFactory;
boolean ssl;
if (builder.sslConfig == null) {
sslContextFactory = getDefaultSslContextFactory();
ssl = sslContextFactory.getTrustStore() != null || sslContextFactory.getTrustStorePath() != null;
} else {
sslContextFactory = builder.sslConfig.createClientContextFactory();
ssl = true;
}
boolean sslOnJava8OrLower = ssl && !Constants.JRE_IS_MINIMUM_JAVA9;
HttpClientTransport transport;
if (builder.useHttp1_1 || sslOnJava8OrLower) {
if (sslOnJava8OrLower && !builder.useHttp1_1) {
log.warn("Create Http2SolrClient with HTTP/1.1 transport since Java 8 or lower versions does not support SSL + HTTP/2");
} else {
log.debug("Create Http2SolrClient with HTTP/1.1 transport");
}
transport = new HttpClientTransportOverHTTP(2);
httpClient = new HttpClient(transport, sslContextFactory);
if (builder.maxConnectionsPerHost != null) httpClient.setMaxConnectionsPerDestination(builder.maxConnectionsPerHost);
} else {
log.debug("Create Http2SolrClient with HTTP/2 transport");
HTTP2Client http2client = new HTTP2Client();
transport = new HttpClientTransportOverHTTP2(http2client);
httpClient = new HttpClient(transport, sslContextFactory);
httpClient.setMaxConnectionsPerDestination(4);
}
httpClient.setExecutor(httpClientExecutor);
httpClient.setStrictEventOrdering(false);
httpClient.setConnectBlocking(true);
httpClient.setFollowRedirects(false);
httpClient.setMaxRequestsQueuedPerDestination(asyncTracker.getMaxRequestsQueuedPerDestination());
httpClient.setUserAgentField(new HttpField(HttpHeader.USER_AGENT, AGENT));
httpClient.setIdleTimeout(idleTimeout);
if (builder.connectionTimeout != null) httpClient.setConnectTimeout(builder.connectionTimeout);
try {
httpClient.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
return httpClient;
}
public void close() {
// we wait for async requests, so far devs don't want to give sugar for this
asyncTracker.waitForComplete();
if (closeClient) {
try {
ExecutorService executor = (ExecutorService) httpClient.getExecutor();
httpClient.setStopTimeout(1000);
httpClient.stop();
ExecutorUtil.shutdownAndAwaitTermination(executor);
} catch (Exception e) {
throw new RuntimeException("Exception on closing client", e);
}
}
assert ObjectReleaseTracker.release(this);
}
public boolean isV2ApiRequest(@SuppressWarnings({"rawtypes"})final SolrRequest request) {
return request instanceof V2Request || request.getPath().contains("/____v2");
}
public long getIdleTimeout() {
return idleTimeout;
}
public static class OutStream implements Closeable{
private final String origCollection;
private final ModifiableSolrParams origParams;
private final OutputStreamContentProvider outProvider;
private final InputStreamResponseListener responseListener;
private final boolean isXml;
public OutStream(String origCollection, ModifiableSolrParams origParams,
OutputStreamContentProvider outProvider, InputStreamResponseListener responseListener, boolean isXml) {
this.origCollection = origCollection;
this.origParams = origParams;
this.outProvider = outProvider;
this.responseListener = responseListener;
this.isXml = isXml;
}
boolean belongToThisStream(@SuppressWarnings({"rawtypes"})SolrRequest solrRequest, String collection) {
ModifiableSolrParams solrParams = new ModifiableSolrParams(solrRequest.getParams());
if (!origParams.toNamedList().equals(solrParams.toNamedList()) || !StringUtils.equals(origCollection, collection)) {
return false;
}
return true;
}
public void write(byte b[]) throws IOException {
this.outProvider.getOutputStream().write(b);
}
public void flush() throws IOException {
this.outProvider.getOutputStream().flush();
}
@Override
public void close() throws IOException {
if (isXml) {
write("".getBytes(FALLBACK_CHARSET));
}
this.outProvider.getOutputStream().close();
}
//TODO this class should be hidden
public InputStreamResponseListener getResponseListener() {
return responseListener;
}
}
public OutStream initOutStream(String baseUrl,
UpdateRequest updateRequest,
String collection) throws IOException {
String contentType = requestWriter.getUpdateContentType();
final ModifiableSolrParams origParams = new ModifiableSolrParams(updateRequest.getParams());
// The parser 'wt=' and 'version=' params are used instead of the
// original params
ModifiableSolrParams requestParams = new ModifiableSolrParams(origParams);
requestParams.set(CommonParams.WT, parser.getWriterType());
requestParams.set(CommonParams.VERSION, parser.getVersion());
String basePath = baseUrl;
if (collection != null)
basePath += "/" + collection;
if (!basePath.endsWith("/"))
basePath += "/";
OutputStreamContentProvider provider = new OutputStreamContentProvider();
Request postRequest = httpClient
.newRequest(basePath + "update"
+ requestParams.toQueryString())
.method(HttpMethod.POST)
.header(HttpHeader.CONTENT_TYPE, contentType)
.content(provider);
decorateRequest(postRequest, updateRequest);
InputStreamResponseListener responseListener = new InputStreamResponseListener();
postRequest.send(responseListener);
boolean isXml = ClientUtils.TEXT_XML.equals(requestWriter.getUpdateContentType());
OutStream outStream = new OutStream(collection, origParams, provider, responseListener,
isXml);
if (isXml) {
outStream.write("".getBytes(FALLBACK_CHARSET));
}
return outStream;
}
public void send(OutStream outStream, @SuppressWarnings({"rawtypes"})SolrRequest req, String collection) throws IOException {
assert outStream.belongToThisStream(req, collection);
this.requestWriter.write(req, outStream.outProvider.getOutputStream());
if (outStream.isXml) {
// check for commit or optimize
SolrParams params = req.getParams();
if (params != null) {
String fmt = null;
if (params.getBool(UpdateParams.OPTIMIZE, false)) {
fmt = "";
} else if (params.getBool(UpdateParams.COMMIT, false)) {
fmt = "";
}
if (fmt != null) {
byte[] content = String.format(Locale.ROOT,
fmt, params.getBool(UpdateParams.WAIT_SEARCHER, false)
+ "")
.getBytes(FALLBACK_CHARSET);
outStream.write(content);
}
}
}
outStream.flush();
}
public NamedList