66import com .azure .core .annotation .ServiceClientBuilder ;
77import com .azure .core .credential .TokenCredential ;
88import com .azure .core .http .HttpClient ;
9+ import com .azure .core .http .HttpHeader ;
910import com .azure .core .http .HttpHeaders ;
1011import com .azure .core .http .HttpPipeline ;
1112import com .azure .core .http .HttpPipelineBuilder ;
13+ import com .azure .core .http .HttpPipelinePosition ;
1214import com .azure .core .http .policy .AddDatePolicy ;
15+ import com .azure .core .http .policy .AddHeadersFromContextPolicy ;
1316import com .azure .core .http .policy .AddHeadersPolicy ;
1417import com .azure .core .http .policy .BearerTokenAuthenticationPolicy ;
1518import com .azure .core .http .policy .HttpLogDetailLevel ;
2023import com .azure .core .http .policy .RequestIdPolicy ;
2124import com .azure .core .http .policy .RetryPolicy ;
2225import com .azure .core .http .policy .UserAgentPolicy ;
26+ import com .azure .core .util .ClientOptions ;
2327import com .azure .core .util .Configuration ;
2428import com .azure .core .util .CoreUtils ;
2529import com .azure .core .util .logging .ClientLogger ;
2630import com .azure .data .schemaregistry .implementation .AzureSchemaRegistry ;
2731import com .azure .data .schemaregistry .implementation .AzureSchemaRegistryBuilder ;
32+
2833import java .net .MalformedURLException ;
2934import java .net .URL ;
3035import java .time .temporal .ChronoUnit ;
@@ -46,11 +51,15 @@ public class SchemaRegistryClientBuilder {
4651 private static final String CLIENT_PROPERTIES = "azure-data-schemaregistry-client.properties" ;
4752 private static final String NAME = "name" ;
4853 private static final String VERSION = "version" ;
49- private static final RetryPolicy DEFAULT_RETRY_POLICY =
50- new RetryPolicy ("retry-after-ms" , ChronoUnit .MILLIS );
54+ private static final RetryPolicy DEFAULT_RETRY_POLICY = new RetryPolicy ("retry-after-ms" , ChronoUnit .MILLIS );
55+ private static final AddHeadersPolicy API_HEADER_POLICY = new AddHeadersPolicy (new HttpHeaders ()
56+ .set ("api-version" , "2020-09-01-preview" ));
5157
5258 private final ConcurrentSkipListMap <String , Function <String , Object >> typeParserMap ;
53- private final List <HttpPipelinePolicy > policies ;
59+
60+ private final List <HttpPipelinePolicy > perCallPolicies = new ArrayList <>();
61+ private final List <HttpPipelinePolicy > perRetryPolicies = new ArrayList <>();
62+
5463 private final String clientName ;
5564 private final String clientVersion ;
5665
@@ -59,26 +68,23 @@ public class SchemaRegistryClientBuilder {
5968 private HttpClient httpClient ;
6069 private Integer maxSchemaMapSize ;
6170 private TokenCredential credential ;
71+ private ClientOptions clientOptions ;
6272 private HttpLogOptions httpLogOptions ;
6373 private HttpPipeline httpPipeline ;
6474 private RetryPolicy retryPolicy ;
75+ private Configuration configuration ;
6576
6677 /**
6778 * Constructor for CachedSchemaRegistryClientBuilder. Supplies client defaults.
6879 */
6980 public SchemaRegistryClientBuilder () {
70- this .policies = new ArrayList <>();
7181 this .httpLogOptions = new HttpLogOptions ();
7282 this .maxSchemaMapSize = null ;
7383 this .typeParserMap = new ConcurrentSkipListMap <>(String .CASE_INSENSITIVE_ORDER );
7484 this .httpClient = null ;
7585 this .credential = null ;
7686 this .retryPolicy = new RetryPolicy ("retry-after-ms" , ChronoUnit .MILLIS );
7787
78- HttpHeaders headers = new HttpHeaders ();
79- headers .put ("api-version" , "2020-09-01-preview" );
80- policies .add (new AddHeadersPolicy (headers ));
81-
8288 Map <String , String > properties = CoreUtils .getProperties (CLIENT_PROPERTIES );
8389 clientName = properties .getOrDefault (NAME , "UnknownName" );
8490 clientVersion = properties .getOrDefault (VERSION , "UnknownVersion" );
@@ -87,8 +93,8 @@ public SchemaRegistryClientBuilder() {
8793 /**
8894 * Sets the service endpoint for the Azure Schema Registry instance.
8995 *
90- * @return The updated {@link SchemaRegistryClientBuilder} object.
9196 * @param endpoint The URL of the Azure Schema Registry instance
97+ * @return The updated {@link SchemaRegistryClientBuilder} object.
9298 * @throws NullPointerException if {@code endpoint} is null
9399 * @throws IllegalArgumentException if {@code endpoint} cannot be parsed into a valid URL
94100 */
@@ -159,8 +165,22 @@ public SchemaRegistryClientBuilder pipeline(HttpPipeline httpPipeline) {
159165 }
160166
161167 /**
162- * Sets the {@link TokenCredential} to use when authenticating HTTP requests for this
163- * {@link SchemaRegistryAsyncClient}.
168+ * Sets the configuration store that is used during construction of the service client.
169+ *
170+ * The default configuration store is a clone of the {@link Configuration#getGlobalConfiguration() global
171+ * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction.
172+ *
173+ * @param configuration The configuration store used to
174+ * @return The updated SchemaRegistryClientBuilder object.
175+ */
176+ public SchemaRegistryClientBuilder configuration (Configuration configuration ) {
177+ this .configuration = configuration ;
178+ return this ;
179+ }
180+
181+ /**
182+ * Sets the {@link TokenCredential} to use when authenticating HTTP requests for this {@link
183+ * SchemaRegistryAsyncClient}.
164184 *
165185 * @param credential {@link TokenCredential}
166186 * @return The updated {@link SchemaRegistryClientBuilder} object.
@@ -171,6 +191,22 @@ public SchemaRegistryClientBuilder credential(TokenCredential credential) {
171191 return this ;
172192 }
173193
194+ /**
195+ * Sets the {@link ClientOptions} which enables various options to be set on the client. For example setting an
196+ * {@code applicationId} using {@link ClientOptions#setApplicationId(String)} to configure the {@link
197+ * UserAgentPolicy} for telemetry/monitoring purposes.
198+ *
199+ * <p>More About <a href="https://azure.github.io/azure-sdk/general_azurecore.html#telemetry-policy">Azure Core:
200+ * Telemetry policy</a>
201+ *
202+ * @param clientOptions {@link ClientOptions}.
203+ * @return The updated SchemaRegistryClientBuilder object.
204+ */
205+ public SchemaRegistryClientBuilder clientOptions (ClientOptions clientOptions ) {
206+ this .clientOptions = clientOptions ;
207+ return this ;
208+ }
209+
174210 /**
175211 * Sets the logging configuration for HTTP requests and responses.
176212 *
@@ -205,72 +241,96 @@ public SchemaRegistryClientBuilder retryPolicy(RetryPolicy retryPolicy) {
205241 * @throws NullPointerException If {@code policy} is {@code null}.
206242 */
207243 public SchemaRegistryClientBuilder addPolicy (HttpPipelinePolicy policy ) {
208- policies .add (Objects .requireNonNull (policy , "'policy' cannot be null." ));
244+ Objects .requireNonNull (policy , "'policy' cannot be null." );
245+
246+ if (policy .getPipelinePosition () == HttpPipelinePosition .PER_CALL ) {
247+ perCallPolicies .add (policy );
248+ } else {
249+ perRetryPolicies .add (policy );
250+ }
251+
209252 return this ;
210253 }
211254
212255 /**
213- * Creates a {@link SchemaRegistryAsyncClient} based on options set in the builder.
214- * Every time {@code buildClient()} is called a new instance of {@link SchemaRegistryAsyncClient} is created.
256+ * Creates a {@link SchemaRegistryAsyncClient} based on options set in the builder. Every time {@code buildClient()}
257+ * is called a new instance of {@link SchemaRegistryAsyncClient} is created.
215258 *
216259 * If {@link #pipeline(HttpPipeline) pipeline} is set, then all HTTP pipeline related settings are ignored.
217260 *
218261 * @return A {@link SchemaRegistryAsyncClient} with the options set from the builder.
219- * @throws NullPointerException if {@link #endpoint(String) endpoint} and
220- * {@link #credential(TokenCredential) credential} are not set.
262+ * @throws NullPointerException if {@link #endpoint(String) endpoint} and {@link #credential(TokenCredential)
263+ * credential} are not set.
221264 */
222265 public SchemaRegistryAsyncClient buildAsyncClient () {
223266 Objects .requireNonNull (credential , "'credential' cannot be null" );
224267 Objects .requireNonNull (endpoint , "'endpoint' cannot be null" );
225268
226- HttpPipeline pipeline = this .httpPipeline ;
269+ Configuration buildConfiguration = (configuration == null )
270+ ? Configuration .getGlobalConfiguration ()
271+ : configuration ;
272+
273+ HttpPipeline buildPipeline = this .httpPipeline ;
227274 // Create a default Pipeline if it is not given
228- if (pipeline == null ) {
275+ if (buildPipeline == null ) {
229276 // Closest to API goes first, closest to wire goes last.
230277 final List <HttpPipelinePolicy > policies = new ArrayList <>();
231278
232- policies .add (new UserAgentPolicy (httpLogOptions .getApplicationId (), clientName , clientVersion ,
233- Configuration . getGlobalConfiguration (). clone () ));
279+ policies .add (new UserAgentPolicy (CoreUtils .getApplicationId (clientOptions , httpLogOptions ), clientName ,
280+ clientVersion , buildConfiguration ));
234281 policies .add (new RequestIdPolicy ());
282+ policies .add (new AddHeadersFromContextPolicy ());
283+ policies .add (API_HEADER_POLICY );
235284
285+ policies .addAll (perCallPolicies );
236286 HttpPolicyProviders .addBeforeRetryPolicies (policies );
237287
238288 policies .add (retryPolicy == null ? DEFAULT_RETRY_POLICY : retryPolicy );
239289
240290 policies .add (new AddDatePolicy ());
241-
242291 policies .add (new BearerTokenAuthenticationPolicy (credential , DEFAULT_SCOPE ));
243292
244- policies .addAll (this .policies );
293+ policies .addAll (perRetryPolicies );
294+
295+ if (clientOptions != null ) {
296+ List <HttpHeader > clientOptionsHeaders = new ArrayList <>();
297+ clientOptions .getHeaders ()
298+ .forEach (header -> clientOptionsHeaders .add (new HttpHeader (header .getName (), header .getValue ())));
299+
300+ if (!CoreUtils .isNullOrEmpty (clientOptionsHeaders )) {
301+ policies .add (new AddHeadersPolicy (new HttpHeaders (clientOptionsHeaders )));
302+ }
303+ }
304+
245305 HttpPolicyProviders .addAfterRetryPolicies (policies );
246306
247307 policies .add (new HttpLoggingPolicy (httpLogOptions ));
248308
249- pipeline = new HttpPipelineBuilder ()
309+ buildPipeline = new HttpPipelineBuilder ()
250310 .policies (policies .toArray (new HttpPipelinePolicy [0 ]))
251311 .httpClient (httpClient )
312+ .clientOptions (clientOptions )
252313 .build ();
253314 }
254315
255316 AzureSchemaRegistry restService = new AzureSchemaRegistryBuilder ()
256317 .endpoint (host )
257- .pipeline (pipeline )
318+ .pipeline (buildPipeline )
258319 .buildClient ();
259320
260- this . maxSchemaMapSize = this . maxSchemaMapSize != null
261- ? this . maxSchemaMapSize
262- : SchemaRegistryAsyncClient . MAX_SCHEMA_MAP_SIZE_DEFAULT ;
321+ int buildMaxSchemaMapSize = ( maxSchemaMapSize == null )
322+ ? SchemaRegistryAsyncClient . MAX_SCHEMA_MAP_SIZE_DEFAULT
323+ : maxSchemaMapSize ;
263324
264- return new SchemaRegistryAsyncClient (restService , maxSchemaMapSize , typeParserMap );
325+ return new SchemaRegistryAsyncClient (restService , buildMaxSchemaMapSize , typeParserMap );
265326 }
266327
267328 /**
268- * Creates synchronous {@link SchemaRegistryClient} instance.
269- * See async builder method for options validation.
329+ * Creates synchronous {@link SchemaRegistryClient} instance. See async builder method for options validation.
270330 *
271331 * @return {@link SchemaRegistryClient} with the options set from the builder.
272- * @throws NullPointerException if {@link #endpoint(String) endpoint} and
273- * {@link #credential(TokenCredential) credential} are not set.
332+ * @throws NullPointerException if {@link #endpoint(String) endpoint} and {@link #credential(TokenCredential)
333+ * credential} are not set.
274334 */
275335 public SchemaRegistryClient buildClient () {
276336 return new SchemaRegistryClient (this .buildAsyncClient ());
0 commit comments