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.client.solrj.impl; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.lang.invoke.MethodHandles; import java.net.ConnectException; import java.net.MalformedURLException; import java.net.SocketTimeoutException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.Principal; 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.Objects; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.mime.FormBodyPart; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.InputStreamBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.apache.solr.client.solrj.ResponseParser; 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.request.RequestWriter; import org.apache.solr.client.solrj.request.V2Request; import org.apache.solr.common.SolrException; 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.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.SolrjNamedThreadFactory; import org.apache.solr.common.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import static org.apache.solr.common.util.Utils.getObjectByPath; /** * A SolrClient implementation that talks directly to a Solr server via HTTP */ public class HttpSolrClient extends BaseHttpSolrClient { private static final String UTF_8 = StandardCharsets.UTF_8.name(); private static final String DEFAULT_PATH = "/select"; private static final long serialVersionUID = -946812319974801896L; /** * User-Agent String. */ public static final String AGENT = "Solr[" + HttpSolrClient.class.getName() + "] 1.0"; private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); static final Class<HttpSolrClient> cacheKey = HttpSolrClient.class; /** * The URL of the Solr server. */ protected volatile String baseUrl; /** * Default value: null / empty. * <p> * Parameters that are added to every request regardless. This may be a place * to add something like an authentication token. */ protected ModifiableSolrParams invariantParams; /** * Default response parser is BinaryResponseParser * <p> * This parser represents the default Response Parser chosen to parse the * response if the parser were not specified as part of the request. * * @see org.apache.solr.client.solrj.impl.BinaryResponseParser */ protected volatile ResponseParser parser; /** * The RequestWriter used to write all requests to Solr * * @see org.apache.solr.client.solrj.request.RequestWriter */ protected volatile RequestWriter requestWriter = new BinaryRequestWriter(); private final HttpClient httpClient; private volatile Boolean followRedirects = false; private volatile boolean useMultiPartPost; private final boolean internalClient; private volatile Set<String> queryParams = Collections.emptySet(); private volatile Integer connectionTimeout; private volatile Integer soTimeout; /** * @deprecated use {@link HttpSolrClient#HttpSolrClient(Builder)} instead, as it is a more extension/subclassing-friendly alternative */ @Deprecated protected HttpSolrClient(String baseURL, HttpClient client, ResponseParser parser, boolean allowCompression) { this(new Builder(baseURL).withHttpClient(client).withResponseParser(parser) .allowCompression(allowCompression)); } /** * The constructor. * * @param baseURL The base url to communicate with the Solr server * @param client Http client instance to use for communication * @param parser Response parser instance to use to decode response from Solr server * @param allowCompression Should compression be allowed ? * @param invariantParams The parameters which should be included with every request. * * @deprecated use {@link HttpSolrClient#HttpSolrClient(Builder)} instead, as it is a more extension/subclassing-friendly alternative */ @Deprecated protected HttpSolrClient(String baseURL, HttpClient client, ResponseParser parser, boolean allowCompression, ModifiableSolrParams invariantParams) { this(new Builder(baseURL).withHttpClient(client).withResponseParser(parser) .allowCompression(allowCompression).withInvariantParams(invariantParams)); } protected HttpSolrClient(Builder builder) { this.baseUrl = builder.baseSolrUrl; if (baseUrl.endsWith("/")) { baseUrl = baseUrl.substring(0, baseUrl.length() - 1); } if (baseUrl.indexOf('?') >= 0) { throw new RuntimeException( "Invalid base url for solrj. The base URL must not contain parameters: " + baseUrl); } if (builder.httpClient != null) { this.httpClient = builder.httpClient; this.internalClient = false; } else { this.internalClient = true; ModifiableSolrParams params = new ModifiableSolrParams(); params.set(HttpClientUtil.PROP_FOLLOW_REDIRECTS, followRedirects); params.set(HttpClientUtil.PROP_ALLOW_COMPRESSION, builder.compression); httpClient = HttpClientUtil.createClient(params); } this.parser = builder.responseParser; this.invariantParams = builder.invariantParams; this.connectionTimeout = builder.connectionTimeoutMillis; this.soTimeout = builder.socketTimeoutMillis; } public Set<String> getQueryParams() { return queryParams; } /** * Expert Method * @param queryParams set of param keys to only send via the query string * Note that the param will be sent as a query string if the key is part * of this Set or the SolrRequest's query params. * @see org.apache.solr.client.solrj.SolrRequest#getQueryParams */ public void setQueryParams(Set<String> queryParams) { this.queryParams = queryParams; } /** * Process the request. If * {@link org.apache.solr.client.solrj.SolrRequest#getResponseParser()} is * null, then use {@link #getParser()} * * @param request * The {@link org.apache.solr.client.solrj.SolrRequest} to process * @return The {@link org.apache.solr.common.util.NamedList} result * @throws IOException If there is a low-level I/O error. * * @see #request(org.apache.solr.client.solrj.SolrRequest, * org.apache.solr.client.solrj.ResponseParser) */ @Override public NamedList<Object> request(final SolrRequest request, String collection) throws SolrServerException, IOException { ResponseParser responseParser = request.getResponseParser(); if (responseParser == null) { responseParser = parser; } return request(request, responseParser, collection); } public NamedList<Object> request(final SolrRequest request, final ResponseParser processor) throws SolrServerException, IOException { return request(request, processor, null); } public NamedList<Object> request(final SolrRequest request, final ResponseParser processor, String collection) throws SolrServerException, IOException { HttpRequestBase method = createMethod(request, collection); setBasicAuthHeader(request, method); if (request.getHeaders() != null) { Map<String, String> headers = request.getHeaders(); for (Map.Entry<String, String> entry : headers.entrySet()) { method.setHeader(entry.getKey(), entry.getValue()); } } return executeMethod(method, request.getUserPrincipal(), processor, isV2ApiRequest(request)); } private boolean isV2ApiRequest(final SolrRequest request) { return request instanceof V2Request || request.getPath().contains("/____v2"); } private void setBasicAuthHeader(SolrRequest request, HttpRequestBase method) throws UnsupportedEncodingException { if (request.getBasicAuthUser() != null && request.getBasicAuthPassword() != null) { String userPass = request.getBasicAuthUser() + ":" + request.getBasicAuthPassword(); String encoded = Base64.byteArrayToBase64(userPass.getBytes(UTF_8)); method.setHeader(new BasicHeader("Authorization", "Basic " + encoded)); } } /** * @lucene.experimental */ public static class HttpUriRequestResponse { public HttpUriRequest httpUriRequest; public Future<NamedList<Object>> future; } /** * @lucene.experimental */ public HttpUriRequestResponse httpUriRequest(final SolrRequest request) throws SolrServerException, IOException { ResponseParser responseParser = request.getResponseParser(); if (responseParser == null) { responseParser = parser; } return httpUriRequest(request, responseParser); } /** * @lucene.experimental */ public HttpUriRequestResponse httpUriRequest(final SolrRequest request, final ResponseParser processor) throws SolrServerException, IOException { HttpUriRequestResponse mrr = new HttpUriRequestResponse(); final HttpRequestBase method = createMethod(request, null); ExecutorService pool = ExecutorUtil.newMDCAwareFixedThreadPool(1, new SolrjNamedThreadFactory("httpUriRequest")); try { MDC.put("HttpSolrClient.url", baseUrl); mrr.future = pool.submit( () -> executeMethod(method, request.getUserPrincipal(), processor, isV2ApiRequest(request))); } finally { pool.shutdown(); MDC.remove("HttpSolrClient.url"); } assert method != null; mrr.httpUriRequest = method; return mrr; } protected ModifiableSolrParams calculateQueryParams(Set<String> queryParamNames, ModifiableSolrParams wparams) { ModifiableSolrParams queryModParams = new ModifiableSolrParams(); if (queryParamNames != null) { for (String param : queryParamNames) { String[] value = wparams.getParams(param); if (value != null) { for (String v : value) { queryModParams.add(param, v); } wparams.remove(param); } } } return queryModParams; } static String changeV2RequestEndpoint(String basePath) throws MalformedURLException { URL oldURL = new URL(basePath); String newPath = oldURL.getPath().replaceFirst("/solr", "/api"); return new URL(oldURL.getProtocol(), oldURL.getHost(), oldURL.getPort(), newPath).toString(); } protected HttpRequestBase createMethod(SolrRequest request, String collection) throws IOException, SolrServerException { if (request instanceof V2RequestSupport) { request = ((V2RequestSupport) request).getV2Request(); } SolrParams params = request.getParams(); RequestWriter.ContentWriter contentWriter = requestWriter.getContentWriter(request); Collection<ContentStream> streams = contentWriter == null ? requestWriter.getContentStreams(request) : null; String path = requestWriter.getPath(request); if (path == null || !path.startsWith("/")) { path = DEFAULT_PATH; } ResponseParser parser = request.getResponseParser(); if (parser == null) { parser = this.parser; } // The parser 'wt=' and 'version=' params are used instead of the original // params ModifiableSolrParams wparams = new ModifiableSolrParams(params); if (parser != null) { wparams.set(CommonParams.WT, parser.getWriterType()); wparams.set(CommonParams.VERSION, parser.getVersion()); } if (invariantParams != null) { wparams.add(invariantParams); } String basePath = baseUrl; if (collection != null) basePath += "/" + collection; if (request instanceof V2Request) { if (System.getProperty("solr.v2RealPath") == null || ((V2Request) request).isForceV2()) { basePath = baseUrl.replace("/solr", "/api"); } else { basePath = baseUrl + "/____v2"; } } if (SolrRequest.METHOD.GET == request.getMethod()) { if (streams != null || contentWriter != null) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "GET can't send streams!"); } return new HttpGet(basePath + path + wparams.toQueryString()); } if (SolrRequest.METHOD.DELETE == request.getMethod()) { return new HttpDelete(basePath + path + wparams.toQueryString()); } if (SolrRequest.METHOD.POST == request.getMethod() || SolrRequest.METHOD.PUT == request.getMethod()) { String url = basePath + path; boolean hasNullStreamName = false; if (streams != null) { for (ContentStream cs : streams) { if (cs.getName() == null) { hasNullStreamName = true; break; } } } boolean isMultipart = ((this.useMultiPartPost && SolrRequest.METHOD.POST == request.getMethod()) || (streams != null && streams.size() > 1)) && !hasNullStreamName; LinkedList<NameValuePair> postOrPutParams = new LinkedList<>(); if (contentWriter != null) { String fullQueryUrl = url + wparams.toQueryString(); HttpEntityEnclosingRequestBase postOrPut = SolrRequest.METHOD.POST == request.getMethod() ? new HttpPost(fullQueryUrl) : new HttpPut(fullQueryUrl); postOrPut.addHeader("Content-Type", contentWriter.getContentType()); postOrPut.setEntity(new BasicHttpEntity() { @Override public boolean isStreaming() { return true; } @Override public void writeTo(OutputStream outstream) throws IOException { contentWriter.write(outstream); } }); return postOrPut; } else if (streams == null || isMultipart) { // send server list and request list as query string params ModifiableSolrParams queryParams = calculateQueryParams(this.queryParams, wparams); queryParams.add(calculateQueryParams(request.getQueryParams(), wparams)); String fullQueryUrl = url + queryParams.toQueryString(); HttpEntityEnclosingRequestBase postOrPut = fillContentStream(request, streams, wparams, isMultipart, postOrPutParams, fullQueryUrl); return postOrPut; } // It is has one stream, it is the post body, put the params in the URL else { String fullQueryUrl = url + wparams.toQueryString(); HttpEntityEnclosingRequestBase postOrPut = SolrRequest.METHOD.POST == request.getMethod() ? new HttpPost(fullQueryUrl) : new HttpPut(fullQueryUrl); fillSingleContentStream(streams, postOrPut); return postOrPut; } } throw new SolrServerException("Unsupported method: " + request.getMethod()); } private void fillSingleContentStream(Collection<ContentStream> streams, HttpEntityEnclosingRequestBase postOrPut) throws IOException { // Single stream as body // Using a loop just to get the first one final ContentStream[] contentStream = new ContentStream[1]; for (ContentStream content : streams) { contentStream[0] = content; break; } Long size = contentStream[0].getSize(); postOrPut.setEntity(new InputStreamEntity(contentStream[0].getStream(), size == null ? -1 : size) { @Override public Header getContentType() { return new BasicHeader("Content-Type", contentStream[0].getContentType()); } @Override public boolean isRepeatable() { return false; } }); } private HttpEntityEnclosingRequestBase fillContentStream(SolrRequest request, Collection<ContentStream> streams, ModifiableSolrParams wparams, boolean isMultipart, LinkedList<NameValuePair> postOrPutParams, String fullQueryUrl) throws IOException { HttpEntityEnclosingRequestBase postOrPut = SolrRequest.METHOD.POST == request.getMethod() ? new HttpPost(fullQueryUrl) : new HttpPut(fullQueryUrl); if (!isMultipart) { postOrPut.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); } List<FormBodyPart> parts = new LinkedList<>(); Iterator<String> iter = wparams.getParameterNamesIterator(); while (iter.hasNext()) { String p = iter.next(); String[] vals = wparams.getParams(p); if (vals != null) { for (String v : vals) { if (isMultipart) { parts.add(new FormBodyPart(p, new StringBody(v, StandardCharsets.UTF_8))); } else { postOrPutParams.add(new BasicNameValuePair(p, v)); } } } } // TODO: remove deprecated - first simple attempt failed, see {@link MultipartEntityBuilder} if (isMultipart && streams != null) { for (ContentStream content : streams) { String contentType = content.getContentType(); if (contentType == null) { contentType = BinaryResponseParser.BINARY_CONTENT_TYPE; // default } String name = content.getName(); if (name == null) { name = ""; } parts.add(new FormBodyPart(name, new InputStreamBody(content.getStream(), ContentType.parse(contentType), content.getName()))); } } if (parts.size() > 0) { MultipartEntity entity = new MultipartEntity(HttpMultipartMode.STRICT); for (FormBodyPart p : parts) { entity.addPart(p); } postOrPut.setEntity(entity); } else { //not using multipart postOrPut.setEntity(new UrlEncodedFormEntity(postOrPutParams, StandardCharsets.UTF_8)); } return postOrPut; } private static final List<String> errPath = Arrays.asList("metadata", "error-class");//Utils.getObjectByPath(err, false,"metadata/error-class") protected NamedList<Object> executeMethod(HttpRequestBase method, Principal userPrincipal, final ResponseParser processor, final boolean isV2Api) throws SolrServerException { method.addHeader("User-Agent", AGENT); org.apache.http.client.config.RequestConfig.Builder requestConfigBuilder = HttpClientUtil .createDefaultRequestConfigBuilder(); if (soTimeout != null) { requestConfigBuilder.setSocketTimeout(soTimeout); } if (connectionTimeout != null) { requestConfigBuilder.setConnectTimeout(connectionTimeout); } if (followRedirects != null) { requestConfigBuilder.setRedirectsEnabled(followRedirects); } method.setConfig(requestConfigBuilder.build()); HttpEntity entity = null; InputStream respBody = null; boolean shouldClose = true; try { // Execute the method. HttpClientContext httpClientRequestContext = HttpClientUtil.createNewHttpClientRequestContext(); if (userPrincipal != null) { // Normally the context contains a static userToken to enable reuse resources. // However, if a personal Principal object exists, we use that instead, also as a means // to transfer authentication information to Auth plugins that wish to intercept the request later httpClientRequestContext.setUserToken(userPrincipal); } final HttpResponse response = httpClient.execute(method, httpClientRequestContext); int httpStatus = response.getStatusLine().getStatusCode(); // Read the contents entity = response.getEntity(); respBody = entity.getContent(); Header ctHeader = response.getLastHeader("content-type"); String contentType; if (ctHeader != null) { contentType = ctHeader.getValue(); } else { contentType = ""; } // handle some http level checks before trying to parse the response switch (httpStatus) { case HttpStatus.SC_OK: case HttpStatus.SC_BAD_REQUEST: case HttpStatus.SC_CONFLICT: // 409 break; case HttpStatus.SC_MOVED_PERMANENTLY: case HttpStatus.SC_MOVED_TEMPORARILY: if (!followRedirects) { throw new SolrServerException( "Server at " + getBaseURL() + " sent back a redirect (" + httpStatus + ")."); } break; default: if (processor == null || "".equals(contentType)) { throw new RemoteSolrException(baseUrl, httpStatus, "non ok status: " + httpStatus + ", message:" + response.getStatusLine().getReasonPhrase(), null); } } if (processor == null || processor instanceof InputStreamResponseParser) { // no processor specified, return raw stream NamedList<Object> rsp = new NamedList<>(); rsp.add("stream", respBody); rsp.add("closeableResponse", response); // Only case where stream should not be closed shouldClose = false; return rsp; } String procCt = processor.getContentType(); if (procCt != null) { String procMimeType = ContentType.parse(procCt).getMimeType().trim().toLowerCase(Locale.ROOT); String mimeType = ContentType.parse(contentType).getMimeType().trim().toLowerCase(Locale.ROOT); if (!procMimeType.equals(mimeType)) { // unexpected mime type String msg = "Expected mime type " + procMimeType + " but got " + mimeType + "."; Header encodingHeader = response.getEntity().getContentEncoding(); String encoding; if (encodingHeader != null) { encoding = encodingHeader.getValue(); } else { encoding = "UTF-8"; // try UTF-8 } try { msg = msg + " " + IOUtils.toString(respBody, encoding); } catch (IOException e) { throw new RemoteSolrException(baseUrl, httpStatus, "Could not parse response with encoding " + encoding, e); } throw new RemoteSolrException(baseUrl, httpStatus, msg, null); } } NamedList<Object> rsp = null; String charset = EntityUtils.getContentCharSet(response.getEntity()); try { rsp = processor.processResponse(respBody, charset); } catch (Exception e) { throw new RemoteSolrException(baseUrl, httpStatus, e.getMessage(), e); } Object error = rsp == null ? null : rsp.get("error"); if (error != null && (isV2Api || String.valueOf(getObjectByPath(error, true, errPath)).endsWith("ExceptionWithErrObject"))) { throw RemoteExecutionException.create(baseUrl, rsp); } if (httpStatus != HttpStatus.SC_OK && !isV2Api) { NamedList<String> metadata = null; String reason = null; try { NamedList err = (NamedList) rsp.get("error"); if (err != null) { reason = (String) err.get("msg"); if (reason == null) { reason = (String) err.get("trace"); } metadata = (NamedList<String>) err.get("metadata"); } } catch (Exception ex) { } if (reason == null) { StringBuilder msg = new StringBuilder(); msg.append(response.getStatusLine().getReasonPhrase()).append("\n\n").append("request: ") .append(method.getURI()); reason = java.net.URLDecoder.decode(msg.toString(), UTF_8); } RemoteSolrException rss = new RemoteSolrException(baseUrl, httpStatus, reason, null); if (metadata != null) rss.setMetadata(metadata); throw rss; } return rsp; } catch (ConnectException e) { throw new SolrServerException("Server refused connection at: " + getBaseURL(), e); } catch (SocketTimeoutException e) { throw new SolrServerException("Timeout occurred while waiting response from server at: " + getBaseURL(), e); } catch (IOException e) { throw new SolrServerException("IOException occurred when talking to server at: " + getBaseURL(), e); } finally { if (shouldClose) { Utils.consumeFully(entity); } } } // ------------------------------------------------------------------- // ------------------------------------------------------------------- /** * Retrieve the default list of parameters are added to every request * regardless. * * @see #invariantParams */ public ModifiableSolrParams getInvariantParams() { return invariantParams; } public String getBaseURL() { return baseUrl; } /** * Change the base-url used when sending requests to Solr. * * Two different paths can be specified as a part of this URL: * * 1) A path pointing directly at a particular core * <pre> * httpSolrClient.setBaseURL("http://my-solr-server:8983/solr/core1"); * QueryResponse resp = httpSolrClient.query(new SolrQuery("*:*")); * </pre> * Note that when a core is provided in the base URL, queries and other requests can be made without mentioning the * core explicitly. However, the client can only send requests to that core. * * 2) The path of the root Solr path ("/solr") * <pre> * httpSolrClient.setBaseURL("http://my-solr-server:8983/solr"); * QueryResponse resp = httpSolrClient.query("core1", new SolrQuery("*:*")); * </pre> * In this case the client is more flexible and can be used to send requests to any cores. The cost of this is that * the core must be specified on each request. */ public void setBaseURL(String baseURL) { this.baseUrl = baseURL; } public ResponseParser getParser() { return parser; } /** * Note: This setter method is <b>not thread-safe</b>. * * @param processor * Default Response Parser chosen to parse the response if the parser * were not specified as part of the request. * @see org.apache.solr.client.solrj.SolrRequest#getResponseParser() */ public void setParser(ResponseParser processor) { parser = processor; } /** * Return the HttpClient this instance uses. */ public HttpClient getHttpClient() { return httpClient; } /** * HttpConnectionParams.setConnectionTimeout * * @param timeout * Timeout in milliseconds * * @deprecated since 7.0 Use {@link Builder} methods instead. */ @Deprecated public void setConnectionTimeout(int timeout) { this.connectionTimeout = timeout; } /** * Set SoTimeout (read timeout). This is desirable * for queries, but probably not for indexing. * * @param timeout * Timeout in milliseconds * s * @deprecated since 7.0 Use {@link Builder} methods instead. */ @Deprecated public void setSoTimeout(int timeout) { this.soTimeout = timeout; } /** * Configure whether the client should follow redirects or not. * <p> * This defaults to false under the assumption that if you are following a * redirect to get to a Solr installation, something is misconfigured * somewhere. * </p> */ public void setFollowRedirects(boolean followRedirects) { this.followRedirects = followRedirects; } public void setRequestWriter(RequestWriter requestWriter) { this.requestWriter = requestWriter; } /** * Close the {@link HttpClientConnectionManager} from the internal client. */ @Override public void close() throws IOException { if (httpClient != null && internalClient) { HttpClientUtil.close(httpClient); } } public boolean isUseMultiPartPost() { return useMultiPartPost; } /** * Set the multipart connection properties */ public void setUseMultiPartPost(boolean useMultiPartPost) { this.useMultiPartPost = useMultiPartPost; } /** * @deprecated since 8.0, catch {@link BaseHttpSolrClient.RemoteSolrException} instead */ @Deprecated public static class RemoteSolrException extends BaseHttpSolrClient.RemoteSolrException { public RemoteSolrException(String remoteHost, int code, String msg, Throwable th) { super(remoteHost, code, msg, th); } } /** * @deprecated since 8.0, catch {@link BaseHttpSolrClient.RemoteExecutionException} instead */ @Deprecated public static class RemoteExecutionException extends BaseHttpSolrClient.RemoteExecutionException { public RemoteExecutionException(String remoteHost, int code, String msg, NamedList meta) { super(remoteHost, code, msg, meta); } } /** * Constructs {@link HttpSolrClient} instances from provided configuration. */ public static class Builder extends SolrClientBuilder<Builder> { protected String baseSolrUrl; protected boolean compression; protected ModifiableSolrParams invariantParams = new ModifiableSolrParams(); public Builder() { this.responseParser = new BinaryResponseParser(); } /** * Specify the base-url for the created client to use when sending requests to Solr. * * Two different paths can be specified as a part of this URL: * * 1) A path pointing directly at a particular core * <pre> * SolrClient client = builder.withBaseSolrUrl("http://my-solr-server:8983/solr/core1").build(); * QueryResponse resp = client.query(new SolrQuery("*:*")); * </pre> * Note that when a core is provided in the base URL, queries and other requests can be made without mentioning the * core explicitly. However, the client can only send requests to that core. * * 2) The path of the root Solr path ("/solr") * <pre> * SolrClient client = builder.withBaseSolrUrl("http://my-solr-server:8983/solr").build(); * QueryResponse resp = client.query("core1", new SolrQuery("*:*")); * </pre> * In this case the client is more flexible and can be used to send requests to any cores. This flexibility though * requires that the core is specified on all requests. */ public Builder withBaseSolrUrl(String baseSolrUrl) { this.baseSolrUrl = baseSolrUrl; return this; } /** * Create a Builder object, based on the provided Solr URL. * * Two different paths can be specified as a part of this URL: * * 1) A path pointing directly at a particular core * <pre> * SolrClient client = new HttpSolrClient.Builder("http://my-solr-server:8983/solr/core1").build(); * QueryResponse resp = client.query(new SolrQuery("*:*")); * </pre> * Note that when a core is provided in the base URL, queries and other requests can be made without mentioning the * core explicitly. However, the client can only send requests to that core. * * 2) The path of the root Solr path ("/solr") * <pre> * SolrClient client = new HttpSolrClient.Builder("http://my-solr-server:8983/solr").build(); * QueryResponse resp = client.query("core1", new SolrQuery("*:*")); * </pre> * In this case the client is more flexible and can be used to send requests to any cores. This flexibility though * requires that the core be specified on all requests. * * By default, compression is not enabled on created HttpSolrClient objects. */ public Builder(String baseSolrUrl) { this.baseSolrUrl = baseSolrUrl; this.responseParser = new BinaryResponseParser(); } /** * Chooses whether created {@link HttpSolrClient}s use compression by default. */ public Builder allowCompression(boolean compression) { this.compression = compression; return this; } /** * Use a delegation token for authenticating via the KerberosPlugin */ public Builder withKerberosDelegationToken(String delegationToken) { if (this.invariantParams.get(DelegationTokenHttpSolrClient.DELEGATION_TOKEN_PARAM) != null) { throw new IllegalStateException( DelegationTokenHttpSolrClient.DELEGATION_TOKEN_PARAM + " is already defined!"); } this.invariantParams.add(DelegationTokenHttpSolrClient.DELEGATION_TOKEN_PARAM, delegationToken); return this; } /** * Adds to the set of params that the created {@link HttpSolrClient} will add on all requests * * @param params a set of parameters to add to the invariant-params list. These params must be unique and may not * duplicate a param already in the invariant list. */ public Builder withInvariantParams(ModifiableSolrParams params) { Objects.requireNonNull(params, "params must be non null!"); for (String name : params.getParameterNames()) { if (this.invariantParams.get(name) != null) { throw new IllegalStateException("parameter " + name + " is redefined."); } } this.invariantParams.add(params); return this; } /** * Create a {@link HttpSolrClient} based on provided configuration. */ public HttpSolrClient build() { if (baseSolrUrl == null) { throw new IllegalArgumentException("Cannot create HttpSolrClient without a valid baseSolrUrl!"); } if (this.invariantParams.get(DelegationTokenHttpSolrClient.DELEGATION_TOKEN_PARAM) == null) { return new HttpSolrClient(this); } else { return new DelegationTokenHttpSolrClient(this); } } @Override public Builder getThis() { return this; } } }