Skip to content

Commit

Permalink
Client enhancements (Azure#191)
Browse files Browse the repository at this point in the history
* Adds consistent implementation of .endpoint() on builders
* Adds SearchService(Async)Client.getIndexClient
* Renames Util -> Parser
  • Loading branch information
noelbundick authored Oct 25, 2019
1 parent 629e850 commit bc05f1b
Show file tree
Hide file tree
Showing 24 changed files with 919 additions and 530 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
package com.azure.search;

import com.azure.core.annotation.ServiceClient;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpPipelineBuilder;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedFluxBase;
import com.azure.core.http.rest.PagedResponse;
Expand All @@ -15,6 +13,7 @@
import com.azure.core.implementation.serializer.SerializerAdapter;
import com.azure.core.implementation.serializer.jackson.JacksonAdapter;
import com.azure.core.util.Context;
import com.azure.core.util.logging.ClientLogger;
import com.azure.search.common.AutoCompletePagedResponse;
import com.azure.search.common.SearchPagedResponse;
import com.azure.search.common.SuggestPagedResponse;
Expand All @@ -26,18 +25,16 @@
import com.azure.search.models.AutocompleteRequest;
import com.azure.search.models.DocumentIndexResult;
import com.azure.search.models.IndexBatch;
import com.azure.search.models.SearchRequest;
import com.azure.search.models.RequestOptions;
import com.azure.search.models.SearchOptions;
import com.azure.search.models.SearchRequest;
import com.azure.search.models.SearchResult;
import com.azure.search.models.SuggestOptions;
import com.azure.search.models.SearchOptions;
import com.azure.search.models.SuggestRequest;
import com.azure.search.models.SuggestResult;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Mono;
import com.azure.core.util.logging.ClientLogger;

import java.util.List;
import java.util.function.Function;
Expand Down Expand Up @@ -72,20 +69,27 @@ public class SearchIndexAsyncClient {
*/
private final String indexName;

/**
* The logger to be used
*/
private final ClientLogger logger = new ClientLogger(SearchIndexAsyncClient.class);

/**
* The underlying REST client to be used to actually interact with the Search service
* The underlying AutoRest client used to interact with the Search service
*/
private final SearchIndexRestClientImpl restClient;

/**
* The pipeline that powers this client.
*/
private final HttpPipeline httpPipeline;

/**
* Package private constructor to be used by {@link SearchIndexClientBuilder}
*/
SearchIndexAsyncClient(
String searchServiceName, String searchDnsSuffix, String indexName, String apiVersion,
HttpClient httpClient,
List<HttpPipelinePolicy> policies) {
HttpPipeline httpPipeline) {
if (StringUtils.isBlank(searchServiceName)) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid searchServiceName"));
}
Expand All @@ -98,26 +102,22 @@ public class SearchIndexAsyncClient {
if (StringUtils.isBlank(apiVersion)) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid apiVersion"));
}
if (httpClient == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid httpClient"));
}
if (policies == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid policies"));
if (httpPipeline == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid httpPipeline"));
}

this.searchServiceName = searchServiceName;
this.searchDnsSuffix = searchDnsSuffix;
this.indexName = indexName;
this.apiVersion = apiVersion;
this.httpPipeline = httpPipeline;

restClient = new SearchIndexRestClientBuilder()
.searchServiceName(searchServiceName)
.indexName(indexName)
.searchDnsSuffix(searchDnsSuffix)
.apiVersion(apiVersion)
.pipeline(new HttpPipelineBuilder()
.httpClient(httpClient)
.policies(policies.toArray(new HttpPipelinePolicy[0])).build())
.pipeline(httpPipeline)
.serializer(SERIALIZER)
.build();
}
Expand All @@ -131,6 +131,14 @@ public String getIndexName() {
return this.indexName;
}

/**
* Gets the {@link HttpPipeline} powering this client.
* @return the pipeline.
*/
HttpPipeline getHttpPipeline() {
return this.httpPipeline;
}

/**
* Uploads a collection of documents to the target index
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package com.azure.search;

import com.azure.core.annotation.ServiceClient;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedFluxBase;
import com.azure.core.http.rest.PagedIterable;
Expand Down Expand Up @@ -48,6 +49,14 @@ public String getIndexName() {
return asyncClient.getIndexName();
}

/**
* Gets the {@link HttpPipeline} powering this client.
* @return the pipeline.
*/
HttpPipeline getHttpPipeline() {
return this.asyncClient.getHttpPipeline();
}

/**
* Uploads a collection of documents to the target index
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,30 @@

import com.azure.core.annotation.ServiceClientBuilder;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.HttpPipelineBuilder;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.util.logging.ClientLogger;
import com.azure.search.common.SearchApiKeyPipelinePolicy;
import org.apache.commons.lang3.StringUtils;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
* Fluent SearchIndexClientBuilder
* for instantiating a {@link SearchIndexClient} or a {@link SearchIndexAsyncClient}
* using {@link SearchIndexClientBuilder#buildClient()} or {@link SearchIndexClientBuilder#buildAsyncClient()}
* This class provides a fluent builder API to help aid the configuration and instantiation of
* {@link SearchIndexClient SearchIndexClients} and {@link SearchIndexAsyncClient SearchIndexAsyncClients}.
* Call {@link #buildClient() buildClient} and {@link #buildAsyncClient() buildAsyncClient} respectively to construct
* an instance of the desired client.
*
* <p>
* The following information must be provided on this builder:
*
* <ul>
* <li>the search service name through {@code .serviceName()}
* <li>the index name through {@code .indexName()}
* <li>the api version through {@code .apiVersion()}
* <li>the api-key though {@code .policy()}</li>
* </ul>
*
* <p>
* Once all the configurations are set on this builder, call {@code .buildClient()} to create a
* {@link SearchIndexClient} or {@code .buildAsyncClient()} to create a {@link SearchIndexAsyncClient}
* The following information must be provided on this builder:
* <ul>
* <li>the search service endpoint through {@code .endpoint()}
* <li>the index name through {@code .indexName()}
* <li>the API key through {@code .credential()}</li>
* </ul>
* </p>
*/
@ServiceClientBuilder(serviceClients = { SearchIndexClient.class, SearchIndexAsyncClient.class})
public class SearchIndexClientBuilder {
Expand Down Expand Up @@ -68,43 +64,16 @@ public SearchIndexClientBuilder apiVersion(String apiVersion) {
}

/**
* Sets search service name
* Sets the search service endpoint
*
* @param endpoint the endpoint URL to the search service
* @return the updated SearchIndexClientBuilder object
* @throws IllegalArgumentException on invalid service endpoint
*/
public SearchIndexClientBuilder serviceEndpoint(String endpoint) throws IllegalArgumentException {
if (StringUtils.isBlank(endpoint)) {
throw logger.logExceptionAsError(
new IllegalArgumentException("Illegal endpoint URL: endpoint cannot be blank"));
}

URL url;
try {
// Using the URL class to validate the given endpoint structure
url = new URL(endpoint);
} catch (MalformedURLException exc) {
throw logger.logExceptionAsError(new IllegalArgumentException("Illegal endpoint URL: " + exc.getMessage()));
}

// Now that we know that the endpoint is in a valid form, extract the host part
// (e.g. http://myservice.search.windows.net ==> myservice.search.windows.net) and verify its structure,
// we expect the service name and domain to be present.
String extractedHost = url.getHost();
if (StringUtils.isBlank(extractedHost) || extractedHost.startsWith(".") || extractedHost.endsWith(".")) {
throw logger.logExceptionAsError(new IllegalArgumentException("Illegal endpoint URL: invalid host"));
}

String[] tokens = StringUtils.split(extractedHost, ".");
if ((tokens.length < 3) || (StringUtils.isBlank(tokens[0]))) {
throw logger.logExceptionAsError(new IllegalArgumentException("Illegal endpoint URL: invalid host"));
}

// split the service name and dns suffix
this.serviceName = tokens[0];
int index = StringUtils.indexOf(extractedHost, ".");
this.searchDnsSuffix = extractedHost.substring(index + 1);
public SearchIndexClientBuilder endpoint(String endpoint) throws IllegalArgumentException {
SearchServiceUrlParser.SearchServiceUrlParts parts = SearchServiceUrlParser.parseServiceUrlParts(endpoint);
this.serviceName = parts.serviceName;
this.searchDnsSuffix = parts.dnsSuffix;
return this;
}

Expand All @@ -131,8 +100,8 @@ public SearchIndexClientBuilder httpClient(HttpClient httpClient) {
}

/**
* Sets the api key to use for requests authentication.
* @param apiKeyCredentials api key for requests authentication
* Sets the api key to use for request authentication.
* @param apiKeyCredentials api key for request authentication
* @throws IllegalArgumentException when the api key is empty
* @return the updated SearchIndexClientBuilder object
* @throws IllegalArgumentException when the api key is empty
Expand Down Expand Up @@ -171,11 +140,15 @@ public SearchIndexAsyncClient buildAsyncClient() {
this.policies.add(new SearchApiKeyPipelinePolicy(apiKeyCredentials));
}

HttpPipeline pipeline = new HttpPipelineBuilder()
.httpClient(httpClient)
.policies(policies.toArray(new HttpPipelinePolicy[0]))
.build();

return new SearchIndexAsyncClient(serviceName,
searchDnsSuffix,
indexName,
apiVersion,
httpClient,
policies);
pipeline);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

import com.azure.core.annotation.ServiceClient;
import com.azure.core.exception.HttpResponseException;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpHeaders;
import com.azure.core.http.HttpPipelineBuilder;
import com.azure.core.http.HttpPipeline;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.rest.PagedFlux;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.Response;
Expand All @@ -19,6 +17,7 @@
import com.azure.core.util.logging.ClientLogger;
import com.azure.search.implementation.SearchServiceRestClientBuilder;
import com.azure.search.implementation.SearchServiceRestClientImpl;
import com.azure.search.models.AccessCondition;
import com.azure.search.models.AnalyzeResult;
import com.azure.search.models.DataSource;
import com.azure.search.models.DataSourceListResult;
Expand All @@ -27,17 +26,15 @@
import com.azure.search.models.Indexer;
import com.azure.search.models.IndexerExecutionInfo;
import com.azure.search.models.IndexerListResult;
import com.azure.search.models.RequestOptions;
import com.azure.search.models.Skillset;
import com.azure.search.models.SkillsetListResult;
import com.azure.search.models.SynonymMap;
import com.azure.search.models.SynonymMapListResult;
import com.azure.search.models.AccessCondition;
import com.azure.search.models.RequestOptions;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -67,13 +64,18 @@ public class SearchServiceAsyncClient {
private final ClientLogger logger = new ClientLogger(SearchServiceAsyncClient.class);

/**
* The underlying REST client to be used to actually interact with the Search service
* The underlying AutoRest client used to interact with the Search service
*/
private final SearchServiceRestClientImpl restClient;

/**
* The pipeline that powers this client.
*/
private final HttpPipeline httpPipeline;

SearchServiceAsyncClient(
String searchServiceName, String searchDnsSuffix, String apiVersion,
HttpClient httpClient, List<HttpPipelinePolicy> policies) {
HttpPipeline httpPipeline) {
if (StringUtils.isBlank(searchServiceName)) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid searchServiceName"));
}
Expand All @@ -83,26 +85,45 @@ public class SearchServiceAsyncClient {
if (StringUtils.isBlank(apiVersion)) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid apiVersion"));
}
if (httpClient == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid httpClient"));
}
if (policies == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid policies"));
if (httpPipeline == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("Invalid httpPipeline"));
}

this.searchServiceName = searchServiceName;
this.searchDnsSuffix = searchDnsSuffix;
this.apiVersion = apiVersion;
this.httpPipeline = httpPipeline;
this.restClient = new SearchServiceRestClientBuilder()
.searchServiceName(searchServiceName)
.searchDnsSuffix(searchDnsSuffix)
.apiVersion(apiVersion)
.pipeline(new HttpPipelineBuilder()
.httpClient(httpClient)
.policies(policies.toArray(new HttpPipelinePolicy[0])).build())
.pipeline(httpPipeline)
.build();
}

/**
* Gets the {@link HttpPipeline} powering this client.
* @return the pipeline.
*/
HttpPipeline getHttpPipeline() {
return this.httpPipeline;
}

/**
* Initializes a new {@link SearchIndexAsyncClient} using the given Index name and the
* same configuration as the SearchServiceAsyncClient.
* @param indexName the name of the Index for the client
* @return a {@link SearchIndexAsyncClient} created from the service client configuration
*/
public SearchIndexAsyncClient getIndexClient(String indexName) {
return new SearchIndexAsyncClient(
searchServiceName,
searchDnsSuffix,
indexName,
apiVersion,
httpPipeline);
}

/**
* Gets Client Api Version.
*
Expand Down
Loading

0 comments on commit bc05f1b

Please sign in to comment.