diff --git a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java index 163d10f60a..384ab3f767 100644 --- a/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java +++ b/azure-client-authentication/src/main/java/com/microsoft/azure/credentials/ApplicationTokenCredentials.java @@ -113,13 +113,14 @@ public ApplicationTokenCredentials withDefaultSubscriptionId(String subscription * * @param credentialsFile A file with credentials, using the standard Java properties format. * and the following keys: - * subscription= - * tenant= - * client= - * key= - * managementURI= - * baseURL= - * authURL= + * subscription=<subscription-id> + * tenant=<tenant-id> + * client=<client-id> + * key=<client-key> + * managementURI=<management-URI> + * baseURL=<base-URL> + * authURL=<authentication-URL> + * * @return The credentials based on the file. * @throws IOException exception thrown from file access errors. */ diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java index 1721e2ff97..04a6af99d9 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureEnvironment.java @@ -7,9 +7,6 @@ package com.microsoft.azure; -import com.microsoft.azure.serializer.AzureJacksonMapperAdapter; -import com.microsoft.rest.RestClient; - /** * An instance of this class describes an environment in Azure. */ @@ -71,7 +68,25 @@ public AzureEnvironment( "https://login.chinacloudapi.cn/", "https://management.core.chinacloudapi.cn/", true, - "https://management.chinacloudapi.cn"); + "https://management.chinacloudapi.cn/"); + + /** + * Provides the settings for authentication with Azure US Government. + */ + public static final AzureEnvironment AZURE_US_GOVERNMENT = new AzureEnvironment( + "https://login.microsoftonline.com/", + "https://management.core.usgovcloudapi.net/", + true, + "https://management.usgovcloudapi.net/"); + + /** + * Provides the settings for authentication with Azure Germany. + */ + public static final AzureEnvironment AZURE_GERMANY = new AzureEnvironment( + "https://login.microsoftonline.de/", + "https://management.core.cloudapi.de/", + true, + "https://management.microsoftazure.de/"); /** * Gets the base URL of the management service. @@ -87,10 +102,10 @@ public String getBaseUrl() { * * @return a builder for the rest client. */ - public RestClient.Builder newRestClientBuilder() { - return new RestClient.Builder(baseURL) - .withInterceptor(new RequestIdHeaderInterceptor()) - .withMapperAdapter(new AzureJacksonMapperAdapter()); + public RestClient.Builder.Buildable newRestClientBuilder() { + return new RestClient.Builder() + .withDefaultBaseUrl(this) + .withInterceptor(new RequestIdHeaderInterceptor()); } /** diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureServiceClient.java b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureServiceClient.java index 08094b67d5..09c8c28fbd 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/AzureServiceClient.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/AzureServiceClient.java @@ -7,18 +7,23 @@ package com.microsoft.azure; -import com.microsoft.azure.serializer.AzureJacksonMapperAdapter; -import com.microsoft.rest.RestClient; -import com.microsoft.rest.ServiceClient; +import com.microsoft.rest.serializer.JacksonMapperAdapter; + +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; /** * ServiceClient is the abstraction for accessing REST operations and their payload data types. */ -public abstract class AzureServiceClient extends ServiceClient { +public abstract class AzureServiceClient { + /** + * The RestClient instance storing all information needed for making REST calls. + */ + private RestClient restClient; + protected AzureServiceClient(String baseUrl) { - this(new RestClient.Builder(baseUrl) - .withInterceptor(new RequestIdHeaderInterceptor()) - .withMapperAdapter(new AzureJacksonMapperAdapter()).build()); + this(new RestClient.Builder().withBaseUrl(baseUrl) + .withInterceptor(new RequestIdHeaderInterceptor()).build()); } /** @@ -27,7 +32,7 @@ protected AzureServiceClient(String baseUrl) { * @param restClient the REST client */ protected AzureServiceClient(RestClient restClient) { - super(restClient); + this.restClient = restClient; } /** @@ -38,4 +43,32 @@ protected AzureServiceClient(RestClient restClient) { public String userAgent() { return "Azure-SDK-For-Java/" + getClass().getPackage().getImplementationVersion(); } + + /** + * @return the {@link RestClient} instance. + */ + public RestClient restClient() { + return restClient; + } + + /** + * @return the Retrofit instance. + */ + public Retrofit retrofit() { + return restClient().retrofit(); + } + + /** + * @return the HTTP client. + */ + public OkHttpClient httpClient() { + return restClient().httpClient(); + } + + /** + * @return the adapter to a Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. + */ + public JacksonMapperAdapter mapperAdapter() { + return restClient().mapperAdapter(); + } } diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGNode.java b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGNode.java index ccc700618e..112130413f 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGNode.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGNode.java @@ -8,6 +8,7 @@ package com.microsoft.azure; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -18,6 +19,7 @@ public class DAGNode extends Node { private List dependentKeys; private int toBeResolved; + private boolean isPreparer; /** * Creates a DAG node. @@ -34,11 +36,11 @@ public DAGNode(String key, T data) { * @return a list of keys of nodes in {@link DAGraph} those are dependents on this node */ List dependentKeys() { - return this.dependentKeys; + return Collections.unmodifiableList(this.dependentKeys); } /** - * mark the node identified by the given key as dependent of this node. + * Mark the node identified by the given key as dependent of this node. * * @param key the id of the dependent node */ @@ -54,12 +56,11 @@ public List dependencyKeys() { } /** - * mark the node identified by the given key as this node's dependency. + * Mark the node identified by the given key as this node's dependency. * * @param dependencyKey the id of the dependency node */ public void addDependency(String dependencyKey) { - toBeResolved++; super.addChild(dependencyKey); } @@ -70,6 +71,30 @@ public boolean hasDependencies() { return this.hasChildren(); } + /** + * Mark or un-mark this node as preparer. + * + * @param isPreparer true if this node needs to be marked as preparer, false otherwise. + */ + public void setPreparer(boolean isPreparer) { + this.isPreparer = isPreparer; + } + + /** + * @return true if this node is marked as preparer + */ + public boolean isPreparer() { + return isPreparer; + } + + /** + * Initialize the node so that traversal can be performed on the parent DAG. + */ + public void initialize() { + this.toBeResolved = this.dependencyKeys().size(); + this.dependentKeys.clear(); + } + /** * @return true if all dependencies of this node are ready to be consumed */ diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java index 8b10bde8b3..58179e0152 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/DAGraph.java @@ -32,6 +32,7 @@ public class DAGraph> extends Graph { public DAGraph(U rootNode) { this.rootNode = rootNode; this.queue = new ArrayDeque<>(); + this.rootNode.setPreparer(true); this.addNode(rootNode); } @@ -52,10 +53,18 @@ public boolean isRootNode(U node) { return this.rootNode == node; } + /** + * @return true if this dag is the preparer responsible for + * preparing the DAG for traversal. + */ + public boolean isPreparer() { + return this.rootNode.isPreparer(); + } + /** * Merge this DAG with another DAG. *

- * this will mark this DAG as a child DAG, the dependencies of nodes in this DAG will be merged + * This will mark this DAG as a child DAG, the dependencies of nodes in this DAG will be merged * with (copied to) the parent DAG * * @param parent the parent DAG @@ -63,7 +72,6 @@ public boolean isRootNode(U node) { public void merge(DAGraph parent) { this.hasParent = true; parent.rootNode.addDependency(this.rootNode.key()); - this.rootNode.addDependent(parent.rootNode.key()); for (Map.Entry entry: graph.entrySet()) { String key = entry.getKey(); if (!parent.graph.containsKey(key)) { @@ -77,19 +85,25 @@ public void merge(DAGraph parent) { * in the DAG with no dependencies. */ public void prepare() { - initializeQueue(); - if (queue.isEmpty()) { - throw new RuntimeException("Found circular dependency"); + if (isPreparer()) { + for (U node : graph.values()) { + // Prepare each node for traversal + node.initialize(); + if (!this.isRootNode(node)) { + // Mark other sub-DAGs as non-preparer + node.setPreparer(false); + } + } + initializeDependentKeys(); + initializeQueue(); } } /** * Gets next node in the DAG which has no dependency or all of it's dependencies are resolved and * ready to be consumed. - *

- * null will be returned when all the nodes are explored * - * @return next node + * @return next node or null if all the nodes have been explored */ public U getNext() { return graph.get(queue.poll()); @@ -111,6 +125,7 @@ public T getNodeData(String key) { * @param completed the node ready to be consumed */ public void reportedCompleted(U completed) { + completed.setPreparer(true); String dependency = completed.key(); for (String dependentKey : graph.get(dependency).dependentKeys()) { DAGNode dependent = graph.get(dependentKey); @@ -122,27 +137,25 @@ public void reportedCompleted(U completed) { } /** - * populate dependents of all nodes. + * Initializes dependents of all nodes. *

- * the DAG will be explored in DFS order and all node's dependents will be identified, + * The DAG will be explored in DFS order and all node's dependents will be identified, * this prepares the DAG for traversal using getNext method, each call to getNext returns next node * in the DAG with no dependencies. */ - public void populateDependentKeys() { - this.queue.clear(); + private void initializeDependentKeys() { visit(new Visitor() { + // This 'visit' will be called only once per each node. @Override public void visit(U node) { if (node.dependencyKeys().isEmpty()) { - queue.add(node.key()); return; } String dependentKey = node.key(); for (String dependencyKey : node.dependencyKeys()) { graph.get(dependencyKey) - .dependentKeys() - .add(dependentKey); + .addDependent(dependentKey); } } }); @@ -159,5 +172,8 @@ private void initializeQueue() { this.queue.add(entry.getKey()); } } + if (queue.isEmpty()) { + throw new RuntimeException("Found circular dependency"); + } } } diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/Graph.java b/azure-client-runtime/src/main/java/com/microsoft/azure/Graph.java index 0cf8e2a7d2..40ceebaa50 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/Graph.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/Graph.java @@ -15,7 +15,7 @@ /** * Type representing a directed graph data structure. *

- * each node in a graph is represented by {@link Node} + * Each node in a graph is represented by {@link Node} * * @param the type of the data stored in the graph's nodes * @param the type of the nodes in the graph diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/Node.java b/azure-client-runtime/src/main/java/com/microsoft/azure/Node.java index 3dc61d8065..cbb83f1d2a 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/Node.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/Node.java @@ -8,6 +8,7 @@ package com.microsoft.azure; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -57,7 +58,7 @@ public boolean hasChildren() { * @return children (neighbours) of this node */ public List children() { - return this.children; + return Collections.unmodifiableList(this.children); } /** diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/ResourceGetExponentialBackoffRetryStrategy.java b/azure-client-runtime/src/main/java/com/microsoft/azure/ResourceGetExponentialBackoffRetryStrategy.java new file mode 100644 index 0000000000..a145fecc67 --- /dev/null +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/ResourceGetExponentialBackoffRetryStrategy.java @@ -0,0 +1,48 @@ +/** + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + */ + +package com.microsoft.azure; + +import com.microsoft.rest.retry.RetryStrategy; +import okhttp3.Response; + +/** + * A retry strategy with backoff parameters for calculating the exponential + * delay between retries for 404s from GET calls. + */ +public class ResourceGetExponentialBackoffRetryStrategy extends RetryStrategy { + /** + * Represents the default number of retries. + */ + private static final int DEFAULT_NUMBER_OF_ATTEMPTS = 3; + + /** + * Creates an instance of the retry strategy. + */ + public ResourceGetExponentialBackoffRetryStrategy() { + this(null, DEFAULT_FIRST_FAST_RETRY); + } + + /** + * Initializes a new instance of the {@link RetryStrategy} class. + * + * @param name The name of the retry strategy. + * @param firstFastRetry true to immediately retry in the first attempt; otherwise, false. + */ + private ResourceGetExponentialBackoffRetryStrategy(String name, boolean firstFastRetry) { + super(name, firstFastRetry); + } + + @Override + public boolean shouldRetry(int retryCount, Response response) { + int code = response.code(); + //CHECKSTYLE IGNORE MagicNumber FOR NEXT 2 LINES + return retryCount < DEFAULT_NUMBER_OF_ATTEMPTS + && code == 404 + && response.request().method().equalsIgnoreCase("GET"); + } +} diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/RestClient.java b/azure-client-runtime/src/main/java/com/microsoft/azure/RestClient.java new file mode 100644 index 0000000000..0ace881f0e --- /dev/null +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/RestClient.java @@ -0,0 +1,351 @@ +/** + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + */ + +package com.microsoft.azure; + +import com.microsoft.azure.serializer.AzureJacksonMapperAdapter; +import com.microsoft.rest.BaseUrlHandler; +import com.microsoft.rest.CustomHeadersInterceptor; +import com.microsoft.rest.UserAgentInterceptor; +import com.microsoft.rest.credentials.ServiceClientCredentials; +import com.microsoft.rest.retry.RetryHandler; +import com.microsoft.rest.serializer.JacksonMapperAdapter; +import okhttp3.ConnectionPool; +import okhttp3.Interceptor; +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; + +import java.lang.reflect.Field; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.net.Proxy; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +/** + * An instance of this class stores the client information for making REST calls. + */ +public class RestClient { + /** The {@link okhttp3.OkHttpClient} object. */ + private OkHttpClient httpClient; + /** The {@link retrofit2.Retrofit} object. */ + private Retrofit retrofit; + /** The credentials to authenticate. */ + private ServiceClientCredentials credentials; + /** The interceptor to handle custom headers. */ + private CustomHeadersInterceptor customHeadersInterceptor; + /** The interceptor to handle base URL. */ + private BaseUrlHandler baseUrlHandler; + /** The adapter to a Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. */ + private JacksonMapperAdapter mapperAdapter; + /** The interceptor to set 'User-Agent' header. */ + private UserAgentInterceptor userAgentInterceptor; + + protected RestClient(OkHttpClient httpClient, + Retrofit retrofit, + ServiceClientCredentials credentials, + CustomHeadersInterceptor customHeadersInterceptor, + UserAgentInterceptor userAgentInterceptor, + BaseUrlHandler baseUrlHandler, + JacksonMapperAdapter mapperAdapter) { + this.httpClient = httpClient; + this.retrofit = retrofit; + this.credentials = credentials; + this.customHeadersInterceptor = customHeadersInterceptor; + this.userAgentInterceptor = userAgentInterceptor; + this.baseUrlHandler = baseUrlHandler; + this.mapperAdapter = mapperAdapter; + } + + /** + * Get the headers interceptor. + * + * @return the headers interceptor. + */ + public CustomHeadersInterceptor headers() { + return customHeadersInterceptor; + } + + /** + * Get the adapter to {@link com.fasterxml.jackson.databind.ObjectMapper}. + * + * @return the Jackson mapper adapter. + */ + public JacksonMapperAdapter mapperAdapter() { + return mapperAdapter; + } + + /** + * Sets the mapper adapter. + * + * @param mapperAdapter an adapter to a Jackson mapper. + * @return the builder itself for chaining. + */ + public RestClient withMapperAdapater(JacksonMapperAdapter mapperAdapter) { + this.mapperAdapter = mapperAdapter; + return this; + } + + /** + * Get the http client. + * + * @return the {@link OkHttpClient} object. + */ + public OkHttpClient httpClient() { + return httpClient; + } + + /** + * Get the retrofit instance. + * + * @return the {@link Retrofit} object. + */ + public Retrofit retrofit() { + return retrofit; + } + + /** + * Get the credentials attached to this REST client. + * + * @return the credentials. + */ + public ServiceClientCredentials credentials() { + return this.credentials; + } + + /** + * The builder class for building a REST client. + */ + public static class Builder { + /** The dynamic base URL with variables wrapped in "{" and "}". */ + protected String baseUrl; + /** The builder to build an {@link OkHttpClient}. */ + protected OkHttpClient.Builder httpClientBuilder; + /** The builder to build a {@link Retrofit}. */ + protected Retrofit.Builder retrofitBuilder; + /** The credentials to authenticate. */ + protected ServiceClientCredentials credentials; + /** The interceptor to handle custom headers. */ + protected CustomHeadersInterceptor customHeadersInterceptor; + /** The interceptor to handle base URL. */ + protected BaseUrlHandler baseUrlHandler; + /** The interceptor to set 'User-Agent' header. */ + protected UserAgentInterceptor userAgentInterceptor; + /** The inner Builder instance. */ + protected Buildable buildable; + + /** + * Creates an instance of the builder with a base URL to the service. + */ + public Builder() { + this(new OkHttpClient.Builder(), new Retrofit.Builder()); + } + + /** + * Creates an instance of the builder with a base URL and 2 custom builders. + * + * @param httpClientBuilder the builder to build an {@link OkHttpClient}. + * @param retrofitBuilder the builder to build a {@link Retrofit}. + */ + public Builder(OkHttpClient.Builder httpClientBuilder, Retrofit.Builder retrofitBuilder) { + if (httpClientBuilder == null) { + throw new IllegalArgumentException("httpClientBuilder == null"); + } + if (retrofitBuilder == null) { + throw new IllegalArgumentException("retrofitBuilder == null"); + } + CookieManager cookieManager = new CookieManager(); + cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL); + customHeadersInterceptor = new CustomHeadersInterceptor(); + baseUrlHandler = new BaseUrlHandler(); + userAgentInterceptor = new UserAgentInterceptor(); + // Set up OkHttp client + this.httpClientBuilder = httpClientBuilder + .cookieJar(new JavaNetCookieJar(cookieManager)) + .addInterceptor(userAgentInterceptor); + this.retrofitBuilder = retrofitBuilder; + this.buildable = new Buildable(); + } + + /** + * Sets the dynamic base URL. + * + * @param baseUrl the base URL to use. + * @return the builder itself for chaining. + */ + public Buildable withBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + return buildable; + } + + /** + * Sets the base URL with the default from the service client. + * + * @param serviceClientClass the service client class containing a default base URL. + * @return the builder itself for chaining. + */ + public Buildable withDefaultBaseUrl(Class serviceClientClass) { + try { + Field field = serviceClientClass.getDeclaredField("DEFAULT_BASE_URL"); + field.setAccessible(true); + baseUrl = (String) field.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new UnsupportedOperationException("Cannot read static field DEFAULT_BASE_URL", e); + } + return buildable; + } + + /** + * Sets the base URL with the default from the Azure Environment. + * + * @param environment the environment the application is running in + * @return the builder itself for chaining + */ + public RestClient.Builder.Buildable withDefaultBaseUrl(AzureEnvironment environment) { + withBaseUrl(environment.getBaseUrl()); + return buildable; + } + + /** + * The inner class from which a Rest Client can be built. + */ + public class Buildable { + /** + * Sets the user agent header. + * + * @param userAgent the user agent header. + * @return the builder itself for chaining. + */ + public Buildable withUserAgent(String userAgent) { + userAgentInterceptor.withUserAgent(userAgent); + return this; + } + + /** + * Sets the credentials. + * + * @param credentials the credentials object. + * @return the builder itself for chaining. + */ + public Buildable withCredentials(ServiceClientCredentials credentials) { + Builder.this.credentials = credentials; + if (credentials != null) { + credentials.applyCredentialsFilter(httpClientBuilder); + } + return this; + } + + /** + * Sets the log level. + * + * @param logLevel the {@link okhttp3.logging.HttpLoggingInterceptor.Level} enum. + * @return the builder itself for chaining. + */ + public Buildable withLogLevel(HttpLoggingInterceptor.Level logLevel) { + httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(logLevel)); + return this; + } + + /** + * Add an interceptor the Http client pipeline. + * + * @param interceptor the interceptor to add. + * @return the builder itself for chaining. + */ + public Buildable withInterceptor(Interceptor interceptor) { + httpClientBuilder.addInterceptor(interceptor); + return this; + } + + /** + * Set the read timeout on the HTTP client. Default is 10 seconds. + * + * @param timeout the timeout numeric value + * @param unit the time unit for the numeric value + * @return the builder itself for chaining + */ + public Buildable withReadTimeout(long timeout, TimeUnit unit) { + httpClientBuilder.readTimeout(timeout, unit); + return this; + } + + /** + * Set the connection timeout on the HTTP client. Default is 10 seconds. + * + * @param timeout the timeout numeric value + * @param unit the time unit for the numeric value + * @return the builder itself for chaining + */ + public Buildable withConnectionTimeout(long timeout, TimeUnit unit) { + httpClientBuilder.connectTimeout(timeout, unit); + return this; + } + + /** + * Set the maximum idle connections for the HTTP client. Default is 5. + * + * @param maxIdleConnections the maximum idle connections + * @return the builder itself for chaining + */ + public Buildable withMaxIdleConnections(int maxIdleConnections) { + httpClientBuilder.connectionPool(new ConnectionPool(maxIdleConnections, 5, TimeUnit.MINUTES)); + return this; + } + + /** + * Sets the executor for async callbacks to run on. + * + * @param executor the executor to execute the callbacks. + * @return the builder itself for chaining + */ + public Buildable withCallbackExecutor(Executor executor) { + retrofitBuilder.callbackExecutor(executor); + return this; + } + + /** + * Sets the proxy for the HTTP client. + * + * @param proxy the proxy to use + * @return the builder itself for chaining + */ + public Buildable withProxy(Proxy proxy) { + httpClientBuilder.proxy(proxy); + return this; + } + + /** + * Build a RestClient with all the current configurations. + * + * @return a {@link RestClient}. + */ + public RestClient build() { + AzureJacksonMapperAdapter mapperAdapter = new AzureJacksonMapperAdapter(); + OkHttpClient httpClient = httpClientBuilder + .addInterceptor(baseUrlHandler) + .addInterceptor(customHeadersInterceptor) + .addInterceptor(new RetryHandler(new ResourceGetExponentialBackoffRetryStrategy())) + .addInterceptor(new RetryHandler()) + .build(); + return new RestClient(httpClient, + retrofitBuilder + .baseUrl(baseUrl) + .client(httpClient) + .addConverterFactory(mapperAdapter.getConverterFactory()) + .build(), + credentials, + customHeadersInterceptor, + userAgentInterceptor, + baseUrlHandler, + mapperAdapter); + } + + } + } +} diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroup.java b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroup.java index 94b4628ff7..26bbbece26 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroup.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroup.java @@ -7,6 +7,9 @@ package com.microsoft.azure; +import com.microsoft.rest.ServiceCall; +import com.microsoft.rest.ServiceCallback; + /** * Represents a group of related tasks. *

@@ -24,11 +27,6 @@ public interface TaskGroup> { */ DAGraph> dag(); - /** - * @return true if this is a root (parent) task group composing other task groups. - */ - boolean isRoot(); - /** * Merges this task group with parent task group. *

@@ -39,6 +37,17 @@ public interface TaskGroup> { */ void merge(TaskGroup parentTaskGroup); + /** + * @return true if the group is responsible for preparing execution of original task in + * this group and all tasks belong other task group it composes. + */ + boolean isPreparer(); + + /** + * Prepare the graph for execution. + */ + void prepare(); + /** * Executes the tasks in the group. *

@@ -48,6 +57,14 @@ public interface TaskGroup> { */ void execute() throws Exception; + /** + * Executes the tasks in the group asynchronously. + * + * @param callback the callback to call on failure or success + * @return the handle to the REST call + */ + ServiceCall executeAsync(ServiceCallback callback); + /** * Gets the result of execution of a task in the group. *

diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java index d0dc430edc..efc8d30e49 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskGroupBase.java @@ -7,15 +7,17 @@ package com.microsoft.azure; +import com.microsoft.rest.ServiceCall; +import com.microsoft.rest.ServiceCallback; + /** * The base implementation of TaskGroup interface. * * @param the result type of the tasks in the group - * @param type representing task in the group */ -public abstract class TaskGroupBase> - implements TaskGroup { - private DAGraph> dag; +public abstract class TaskGroupBase + implements TaskGroup> { + private DAGraph, DAGNode>> dag; /** * Creates TaskGroupBase. @@ -23,39 +25,57 @@ public abstract class TaskGroupBase> * @param rootTaskItemId the id of the root task in this task group * @param rootTaskItem the root task */ - public TaskGroupBase(String rootTaskItemId, U rootTaskItem) { + public TaskGroupBase(String rootTaskItemId, TaskItem rootTaskItem) { this.dag = new DAGraph<>(new DAGNode<>(rootTaskItemId, rootTaskItem)); } @Override - public DAGraph> dag() { + public DAGraph, DAGNode>> dag() { return dag; } @Override - public boolean isRoot() { - return !dag.hasParent(); + public boolean isPreparer() { + return dag.isPreparer(); } @Override - public void merge(TaskGroup parentTaskGroup) { + public void merge(TaskGroup> parentTaskGroup) { dag.merge(parentTaskGroup.dag()); } @Override - public void execute() throws Exception { - if (isRoot()) { + public void prepare() { + if (isPreparer()) { dag.prepare(); - DAGNode nextNode = dag.getNext(); - while (nextNode != null) { - if (dag.isRootNode(nextNode)) { - executeRootTask(nextNode.data()); - } else { - nextNode.data().execute(); - } - dag.reportedCompleted(nextNode); - nextNode = dag.getNext(); - } + } + } + + @Override + public void execute() throws Exception { + DAGNode> nextNode = dag.getNext(); + if (nextNode == null) { + return; + } + + if (dag.isRootNode(nextNode)) { + executeRootTask(nextNode.data()); + } else { + nextNode.data().execute(this, nextNode); + } + } + + @Override + public ServiceCall executeAsync(final ServiceCallback callback) { + final DAGNode> nextNode = dag.getNext(); + if (nextNode == null) { + return null; + } + + if (dag.isRootNode(nextNode)) { + return executeRootTaskAsync(nextNode.data(), callback); + } else { + return nextNode.data().executeAsync(this, nextNode, callback); } } @@ -65,14 +85,27 @@ public T taskResult(String taskId) { } /** - * executes the root task in this group. + * Executes the root task in this group. *

- * this method will be invoked when all the task dependencies of the root task are finished + * This method will be invoked when all the task dependencies of the root task are finished * executing, at this point root task can be executed by consuming the result of tasks it * depends on. * * @param task the root task in this group * @throws Exception the exception */ - public abstract void executeRootTask(U task) throws Exception; + public abstract void executeRootTask(TaskItem task) throws Exception; + + /** + * Executes the root task in this group asynchronously. + *

+ * This method will be invoked when all the task dependencies of the root task are finished + * executing, at this point root task can be executed by consuming the result of tasks it + * depends on. + * + * @param task the root task in this group + * @param callback the callback when the task fails or succeeds + * @return the handle to the REST call + */ + public abstract ServiceCall executeRootTaskAsync(TaskItem task, ServiceCallback callback); } diff --git a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskItem.java b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskItem.java index 7df830f69b..fb74c23845 100644 --- a/azure-client-runtime/src/main/java/com/microsoft/azure/TaskItem.java +++ b/azure-client-runtime/src/main/java/com/microsoft/azure/TaskItem.java @@ -7,6 +7,9 @@ package com.microsoft.azure; +import com.microsoft.rest.ServiceCall; +import com.microsoft.rest.ServiceCallback; + /** * Type representing a task in a task group {@link TaskGroup}. * @@ -22,7 +25,22 @@ public interface TaskItem { * Executes the task. *

* once executed the result will be available through result getter + * + * @param taskGroup the task group dispatching tasks + * @param node the node the task item is associated with * @throws Exception exception */ - void execute() throws Exception; + void execute(TaskGroup> taskGroup, DAGNode> node) throws Exception; + + /** + * Executes the task asynchronously. + *

+ * once executed the result will be available through result getter + + * @param taskGroup the task group dispatching tasks + * @param node the node the task item is associated with + * @param callback callback to call on success or failure + * @return the handle of the REST call + */ + ServiceCall executeAsync(TaskGroup> taskGroup, DAGNode> node, ServiceCallback callback); } diff --git a/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTest.java b/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTest.java index 8c1e12dd70..f3b278797e 100644 --- a/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTest.java +++ b/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTest.java @@ -64,7 +64,7 @@ public void testDAGraphGetNext() { dag.addNode(nodeH); dag.addNode(nodeI); - dag.populateDependentKeys(); + dag.prepare(); DAGNode nextNode = dag.getNext(); int i = 0; while (nextNode != null) { diff --git a/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTests.java b/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTests.java index e368b04c89..985fe306f0 100644 --- a/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTests.java +++ b/azure-client-runtime/src/test/java/com/microsoft/azure/DAGraphTests.java @@ -71,7 +71,7 @@ public void testDAGraphGetNext() { dag.addNode(nodeH); dag.addNode(nodeI); - dag.populateDependentKeys(); + dag.prepare(); DAGNode nextNode = dag.getNext(); int i = 0; while (nextNode != null) { diff --git a/azure-client-runtime/src/test/java/com/microsoft/azure/RequestIdHeaderInterceptorTests.java b/azure-client-runtime/src/test/java/com/microsoft/azure/RequestIdHeaderInterceptorTests.java index e8cce598b0..060336cd23 100644 --- a/azure-client-runtime/src/test/java/com/microsoft/azure/RequestIdHeaderInterceptorTests.java +++ b/azure-client-runtime/src/test/java/com/microsoft/azure/RequestIdHeaderInterceptorTests.java @@ -7,24 +7,25 @@ package com.microsoft.azure; -import com.microsoft.azure.serializer.AzureJacksonMapperAdapter; -import com.microsoft.rest.RestClient; import com.microsoft.rest.retry.RetryHandler; -import okhttp3.Interceptor; -import okhttp3.Protocol; -import okhttp3.Request; -import okhttp3.Response; + import org.junit.Assert; import org.junit.Test; import java.io.IOException; +import okhttp3.Interceptor; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; + public class RequestIdHeaderInterceptorTests { private static final String REQUEST_ID_HEADER = "x-ms-client-request-id"; @Test public void newRequestIdForEachCall() throws Exception { - RestClient restClient = new RestClient.Builder("http://localhost") + RestClient restClient = new RestClient.Builder() + .withBaseUrl("http://localhost") .withInterceptor(new RequestIdHeaderInterceptor()) .withInterceptor(new Interceptor() { private String firstRequestId = null; @@ -45,7 +46,6 @@ public Response intercept(Chain chain) throws IOException { .protocol(Protocol.HTTP_1_1).build(); } }) - .withMapperAdapter(new AzureJacksonMapperAdapter()) .build(); AzureServiceClient serviceClient = new AzureServiceClient(restClient) { }; Response response = serviceClient.restClient().httpClient() @@ -58,11 +58,13 @@ public Response intercept(Chain chain) throws IOException { @Test public void sameRequestIdForRetry() throws Exception { - RestClient restClient = new RestClient.Builder("http://localhost") + RestClient restClient = new RestClient.Builder() + .withBaseUrl("http://localhost") .withInterceptor(new RequestIdHeaderInterceptor()) .withInterceptor(new RetryHandler()) .withInterceptor(new Interceptor() { private String firstRequestId = null; + @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); @@ -80,7 +82,6 @@ public Response intercept(Chain chain) throws IOException { .protocol(Protocol.HTTP_1_1).build(); } }) - .withMapperAdapter(new AzureJacksonMapperAdapter()) .build(); AzureServiceClient serviceClient = new AzureServiceClient(restClient) { }; Response response = serviceClient.restClient().httpClient() diff --git a/client-runtime/src/main/java/com/microsoft/rest/RestClient.java b/client-runtime/src/main/java/com/microsoft/rest/RestClient.java deleted file mode 100644 index 2546396423..0000000000 --- a/client-runtime/src/main/java/com/microsoft/rest/RestClient.java +++ /dev/null @@ -1,245 +0,0 @@ -/** - * - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * - */ - -package com.microsoft.rest; - -import com.microsoft.rest.credentials.ServiceClientCredentials; -import com.microsoft.rest.retry.RetryHandler; -import com.microsoft.rest.serializer.JacksonMapperAdapter; - -import java.net.CookieManager; -import java.net.CookiePolicy; - -import okhttp3.Interceptor; -import okhttp3.JavaNetCookieJar; -import okhttp3.OkHttpClient; -import okhttp3.logging.HttpLoggingInterceptor; -import retrofit2.Retrofit; - -/** - * An instance of this class stores the client information for making REST calls. - */ -public final class RestClient { - /** The {@link okhttp3.OkHttpClient} object. */ - private OkHttpClient httpClient; - /** The {@link retrofit2.Retrofit} object. */ - private Retrofit retrofit; - /** The credentials to authenticate. */ - private ServiceClientCredentials credentials; - /** The interceptor to handle custom headers. */ - private CustomHeadersInterceptor customHeadersInterceptor; - /** The interceptor to handle base URL. */ - private BaseUrlHandler baseUrlHandler; - /** The adapter to a Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. */ - private JacksonMapperAdapter mapperAdapter; - /** The interceptor to set 'User-Agent' header. */ - private UserAgentInterceptor userAgentInterceptor; - - private RestClient(OkHttpClient httpClient, - Retrofit retrofit, - ServiceClientCredentials credentials, - CustomHeadersInterceptor customHeadersInterceptor, - UserAgentInterceptor userAgentInterceptor, - BaseUrlHandler baseUrlHandler, - JacksonMapperAdapter mapperAdapter) { - this.httpClient = httpClient; - this.retrofit = retrofit; - this.credentials = credentials; - this.customHeadersInterceptor = customHeadersInterceptor; - this.userAgentInterceptor = userAgentInterceptor; - this.baseUrlHandler = baseUrlHandler; - this.mapperAdapter = mapperAdapter; - } - - /** - * Get the headers interceptor. - * - * @return the headers interceptor. - */ - public CustomHeadersInterceptor headers() { - return customHeadersInterceptor; - } - - /** - * Get the adapter to {@link com.fasterxml.jackson.databind.ObjectMapper}. - * - * @return the Jackson mapper adapter. - */ - public JacksonMapperAdapter mapperAdapter() { - return mapperAdapter; - } - - /** - * Get the http client. - * - * @return the {@link OkHttpClient} object. - */ - public OkHttpClient httpClient() { - return httpClient; - } - - /** - * Get the retrofit instance. - * - * @return the {@link Retrofit} object. - */ - public Retrofit retrofit() { - return retrofit; - } - - /** - * Get the credentials attached to this REST client. - * - * @return the credentials. - */ - public ServiceClientCredentials credentials() { - return this.credentials; - } - - /** - * The builder class for building a REST client. - */ - public static class Builder { - /** The builder to build an {@link OkHttpClient}. */ - private OkHttpClient.Builder httpClientBuilder; - /** The builder to build a {@link Retrofit}. */ - private Retrofit.Builder retrofitBuilder; - /** The credentials to authenticate. */ - private ServiceClientCredentials credentials; - /** The interceptor to handle custom headers. */ - private CustomHeadersInterceptor customHeadersInterceptor; - /** The interceptor to handle base URL. */ - private BaseUrlHandler baseUrlHandler; - /** The adapter to a Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. */ - private JacksonMapperAdapter mapperAdapter; - /** The interceptor to set 'User-Agent' header. */ - private UserAgentInterceptor userAgentInterceptor; - - /** - * Creates an instance of the builder with a base URL to the service. - * - * @param baseUrl the dynamic base URL with variables wrapped in "{" and "}". - */ - public Builder(String baseUrl) { - this(baseUrl, new OkHttpClient.Builder(), new Retrofit.Builder()); - } - - /** - * Creates an instance of the builder with a base URL and 2 custom builders. - * - * @param baseUrl the dynamic base URL with variables wrapped in "{" and "}". - * @param httpClientBuilder the builder to build an {@link OkHttpClient}. - * @param retrofitBuilder the builder to build a {@link Retrofit}. - */ - public Builder(String baseUrl, OkHttpClient.Builder httpClientBuilder, Retrofit.Builder retrofitBuilder) { - if (baseUrl == null) { - throw new IllegalArgumentException("baseUrl == null"); - } - if (httpClientBuilder == null) { - throw new IllegalArgumentException("httpClientBuilder == null"); - } - if (retrofitBuilder == null) { - throw new IllegalArgumentException("retrofitBuilder == null"); - } - CookieManager cookieManager = new CookieManager(); - cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL); - customHeadersInterceptor = new CustomHeadersInterceptor(); - baseUrlHandler = new BaseUrlHandler(); - userAgentInterceptor = new UserAgentInterceptor(); - // Set up OkHttp client - this.httpClientBuilder = httpClientBuilder - .cookieJar(new JavaNetCookieJar(cookieManager)) - .addInterceptor(userAgentInterceptor); - // Set up rest adapter - this.retrofitBuilder = retrofitBuilder.baseUrl(baseUrl); - } - - /** - * Sets the user agent header. - * - * @param userAgent the user agent header. - * @return the builder itself for chaining. - */ - public Builder withUserAgent(String userAgent) { - this.userAgentInterceptor.setUserAgent(userAgent); - return this; - } - - /** - * Sets the mapper adapter. - * - * @param mapperAdapter an adapter to a Jackson mapper. - * @return the builder itself for chaining. - */ - public Builder withMapperAdapter(JacksonMapperAdapter mapperAdapter) { - this.mapperAdapter = mapperAdapter; - return this; - } - - /** - * Sets the credentials. - * - * @param credentials the credentials object. - * @return the builder itself for chaining. - */ - public Builder withCredentials(ServiceClientCredentials credentials) { - this.credentials = credentials; - if (credentials != null) { - credentials.applyCredentialsFilter(httpClientBuilder); - } - return this; - } - - /** - * Sets the log level. - * - * @param logLevel the {@link okhttp3.logging.HttpLoggingInterceptor.Level} enum. - * @return the builder itself for chaining. - */ - public Builder withLogLevel(HttpLoggingInterceptor.Level logLevel) { - this.httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(logLevel)); - return this; - } - - /** - * Add an interceptor the Http client pipeline. - * - * @param interceptor the interceptor to add. - * @return the builder itself for chaining. - */ - public Builder withInterceptor(Interceptor interceptor) { - this.httpClientBuilder.addInterceptor(interceptor); - return this; - } - - /** - * Build a RestClient with all the current configurations. - * - * @return a {@link RestClient}. - */ - public RestClient build() { - if (mapperAdapter == null) { - throw new IllegalArgumentException("Please set mapper adapter."); - } - OkHttpClient httpClient = httpClientBuilder - .addInterceptor(baseUrlHandler) - .addInterceptor(customHeadersInterceptor) - .addInterceptor(new RetryHandler()) - .build(); - return new RestClient(httpClient, - retrofitBuilder - .client(httpClient) - .addConverterFactory(mapperAdapter.getConverterFactory()) - .build(), - credentials, - customHeadersInterceptor, - userAgentInterceptor, - baseUrlHandler, - mapperAdapter); - } - } -} diff --git a/client-runtime/src/main/java/com/microsoft/rest/ServiceClient.java b/client-runtime/src/main/java/com/microsoft/rest/ServiceClient.java index 674b6a1bc6..8311a243de 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/ServiceClient.java +++ b/client-runtime/src/main/java/com/microsoft/rest/ServiceClient.java @@ -7,16 +7,26 @@ package com.microsoft.rest; +import com.microsoft.rest.retry.RetryHandler; import com.microsoft.rest.serializer.JacksonMapperAdapter; +import java.net.CookieManager; +import java.net.CookiePolicy; + +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; +import retrofit2.Retrofit; + /** * ServiceClient is the abstraction for accessing REST operations and their payload data types. */ public abstract class ServiceClient { - /** - * The builder for building the OkHttp client. - */ - private RestClient restClient; + /** The HTTP client. */ + private OkHttpClient httpClient; + /** The Retrofit instance. */ + private Retrofit retrofit; + /** The adapter to a Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. */ + private JacksonMapperAdapter mapperAdapter; /** * Initializes a new instance of the ServiceClient class. @@ -24,27 +34,55 @@ public abstract class ServiceClient { * @param baseUrl the service endpoint */ protected ServiceClient(String baseUrl) { - this(new RestClient.Builder(baseUrl) - .withMapperAdapter(new JacksonMapperAdapter()).build()); + this(baseUrl, new OkHttpClient.Builder(), new Retrofit.Builder()); } /** * Initializes a new instance of the ServiceClient class. * - * @param restClient the builder to build up an REST client */ - protected ServiceClient(RestClient restClient) { - if (restClient == null) { - throw new IllegalArgumentException("restClient == null"); + protected ServiceClient(String baseUrl, OkHttpClient.Builder clientBuilder, Retrofit.Builder restBuilder) { + if (clientBuilder == null) { + throw new IllegalArgumentException("clientBuilder == null"); } - this.restClient = restClient; + if (restBuilder == null) { + throw new IllegalArgumentException("restBuilder == null"); + } + this.mapperAdapter = new JacksonMapperAdapter(); + CookieManager cookieManager = new CookieManager(); + cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL); + this.httpClient = clientBuilder + .cookieJar(new JavaNetCookieJar(cookieManager)) + .addInterceptor(new UserAgentInterceptor()) + .addInterceptor(new BaseUrlHandler()) + .addInterceptor(new CustomHeadersInterceptor()) + .addInterceptor(new RetryHandler()) + .build(); + this.retrofit = restBuilder + .baseUrl(baseUrl) + .client(httpClient) + .addConverterFactory(mapperAdapter.getConverterFactory()) + .build(); + } + + /** + * @return the Retrofit instance. + */ + public Retrofit retrofit() { + return this.retrofit; + } + + /** + * @return the HTTP client. + */ + public OkHttpClient httpClient() { + return this.httpClient; } /** - * Get the list of interceptors the OkHttp client will execute. - * @return the list of interceptors + * @return the adapter to a Jackson {@link com.fasterxml.jackson.databind.ObjectMapper}. */ - public RestClient restClient() { - return this.restClient; + public JacksonMapperAdapter mapperAdapter() { + return this.mapperAdapter; } } diff --git a/client-runtime/src/main/java/com/microsoft/rest/UserAgentInterceptor.java b/client-runtime/src/main/java/com/microsoft/rest/UserAgentInterceptor.java index ac4a5ec5a7..7b822078d7 100644 --- a/client-runtime/src/main/java/com/microsoft/rest/UserAgentInterceptor.java +++ b/client-runtime/src/main/java/com/microsoft/rest/UserAgentInterceptor.java @@ -39,18 +39,22 @@ public UserAgentInterceptor() { * Overwrite the User-Agent header. * * @param userAgent the new user agent value. + * @return the user agent interceptor itself */ - public void setUserAgent(String userAgent) { + public UserAgentInterceptor withUserAgent(String userAgent) { this.userAgent = userAgent; + return this; } /** * Append a text to the User-Agent header. * * @param userAgent the user agent value to append. + * @return the user agent interceptor itself */ - public void appendUserAgent(String userAgent) { + public UserAgentInterceptor appendUserAgent(String userAgent) { this.userAgent += " " + userAgent; + return this; } @Override diff --git a/client-runtime/src/test/java/com/microsoft/rest/CredentialsTests.java b/client-runtime/src/test/java/com/microsoft/rest/CredentialsTests.java index 3e05c5d723..d21de3ef9b 100644 --- a/client-runtime/src/test/java/com/microsoft/rest/CredentialsTests.java +++ b/client-runtime/src/test/java/com/microsoft/rest/CredentialsTests.java @@ -9,7 +9,6 @@ import com.microsoft.rest.credentials.BasicAuthenticationCredentials; import com.microsoft.rest.credentials.TokenCredentials; -import com.microsoft.rest.serializer.JacksonMapperAdapter; import org.junit.Assert; import org.junit.Test; @@ -26,38 +25,34 @@ public class CredentialsTests { @Test public void basicCredentialsTest() throws Exception { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); - Retrofit.Builder retrofitBuilder = new Retrofit.Builder(); BasicAuthenticationCredentials credentials = new BasicAuthenticationCredentials("user", "pass"); - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost", clientBuilder, retrofitBuilder) - .withMapperAdapter(new JacksonMapperAdapter()) - .withCredentials(credentials) - .withInterceptor(new Interceptor() { - @Override - public Response intercept(Chain chain) throws IOException { - String header = chain.request().header("Authorization"); - Assert.assertEquals("Basic dXNlcjpwYXNz", header); - return new Response.Builder() - .request(chain.request()) - .code(200) - .protocol(Protocol.HTTP_1_1) - .build(); - } - }); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient().newCall(new Request.Builder().url("http://localhost").build()).execute(); + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + credentials.applyCredentialsFilter(clientBuilder); + clientBuilder.addInterceptor( + new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + String header = chain.request().header("Authorization"); + Assert.assertEquals("Basic dXNlcjpwYXNz", header); + return new Response.Builder() + .request(chain.request()) + .code(200) + .protocol(Protocol.HTTP_1_1) + .build(); + } + }); + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, new Retrofit.Builder()) { }; + Response response = serviceClient.httpClient().newCall(new Request.Builder().url("http://localhost").build()).execute(); Assert.assertEquals(200, response.code()); } @Test public void tokenCredentialsTest() throws Exception { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); - Retrofit.Builder retrofitBuilder = new Retrofit.Builder(); TokenCredentials credentials = new TokenCredentials(null, "this_is_a_token"); - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost", clientBuilder, retrofitBuilder) - .withMapperAdapter(new JacksonMapperAdapter()) - .withCredentials(credentials) - .withInterceptor(new Interceptor() { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + credentials.applyCredentialsFilter(clientBuilder); + clientBuilder.addInterceptor( + new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { String header = chain.request().header("Authorization"); @@ -69,8 +64,8 @@ public Response intercept(Chain chain) throws IOException { .build(); } }); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient().newCall(new Request.Builder().url("http://localhost").build()).execute(); + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, new Retrofit.Builder()) { }; + Response response = serviceClient.httpClient().newCall(new Request.Builder().url("http://localhost").build()).execute(); Assert.assertEquals(200, response.code()); } } diff --git a/client-runtime/src/test/java/com/microsoft/rest/RetryHandlerTests.java b/client-runtime/src/test/java/com/microsoft/rest/RetryHandlerTests.java index 97c46f6fe4..068e57b214 100644 --- a/client-runtime/src/test/java/com/microsoft/rest/RetryHandlerTests.java +++ b/client-runtime/src/test/java/com/microsoft/rest/RetryHandlerTests.java @@ -9,7 +9,11 @@ import com.microsoft.rest.retry.RetryHandler; -import com.microsoft.rest.serializer.JacksonMapperAdapter; +import org.junit.Assert; +import org.junit.Test; + +import java.io.IOException; + import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Protocol; @@ -17,11 +21,6 @@ import okhttp3.Response; import retrofit2.Retrofit; -import org.junit.Assert; -import org.junit.Test; - -import java.io.IOException; - public class RetryHandlerTests { @Test public void exponentialRetryEndOn501() throws Exception { @@ -42,10 +41,8 @@ public Response intercept(Chain chain) throws IOException { .build(); } }); - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost", clientBuilder, retrofitBuilder) - .withMapperAdapter(new JacksonMapperAdapter()); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient().newCall( + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, retrofitBuilder) { }; + Response response = serviceClient.httpClient().newCall( new Request.Builder().url("http://localhost").get().build()).execute(); Assert.assertEquals(501, response.code()); } @@ -69,10 +66,8 @@ public Response intercept(Chain chain) throws IOException { .build(); } }); - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost", clientBuilder, retrofitBuilder) - .withMapperAdapter(new JacksonMapperAdapter()); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient().newCall( + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, retrofitBuilder) { }; + Response response = serviceClient.httpClient().newCall( new Request.Builder().url("http://localhost").get().build()).execute(); Assert.assertEquals(500, response.code()); } diff --git a/client-runtime/src/test/java/com/microsoft/rest/ServiceClientTests.java b/client-runtime/src/test/java/com/microsoft/rest/ServiceClientTests.java index 6423ef23d8..9d76292d20 100644 --- a/client-runtime/src/test/java/com/microsoft/rest/ServiceClientTests.java +++ b/client-runtime/src/test/java/com/microsoft/rest/ServiceClientTests.java @@ -7,10 +7,8 @@ package com.microsoft.rest; -import com.microsoft.rest.serializer.JacksonMapperAdapter; import org.junit.Assert; import org.junit.Test; -import retrofit2.Retrofit; import java.io.IOException; @@ -19,6 +17,7 @@ import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; +import retrofit2.Retrofit; public class ServiceClientTests { @Test @@ -39,10 +38,8 @@ public Response intercept(Chain chain) throws IOException { .build(); } }); - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost", clientBuilder, retrofitBuilder) - .withMapperAdapter(new JacksonMapperAdapter()); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient().newCall(new Request.Builder().url("http://localhost").build()).execute(); + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, retrofitBuilder) { }; + Response response = serviceClient.httpClient().newCall(new Request.Builder().url("http://localhost").build()).execute(); Assert.assertEquals(200, response.code()); } diff --git a/client-runtime/src/test/java/com/microsoft/rest/UserAgentTests.java b/client-runtime/src/test/java/com/microsoft/rest/UserAgentTests.java index 35970714e3..9aa60e5b26 100644 --- a/client-runtime/src/test/java/com/microsoft/rest/UserAgentTests.java +++ b/client-runtime/src/test/java/com/microsoft/rest/UserAgentTests.java @@ -7,23 +7,24 @@ package com.microsoft.rest; -import com.microsoft.rest.serializer.JacksonMapperAdapter; - import org.junit.Assert; import org.junit.Test; import java.io.IOException; import okhttp3.Interceptor; +import okhttp3.OkHttpClient; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; +import retrofit2.Retrofit; public class UserAgentTests { @Test public void defaultUserAgentTests() throws Exception { - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost") - .withInterceptor(new Interceptor() { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() + .addInterceptor(new UserAgentInterceptor()) + .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { String header = chain.request().header("User-Agent"); @@ -34,20 +35,18 @@ public Response intercept(Chain chain) throws IOException { .protocol(Protocol.HTTP_1_1) .build(); } - }) - .withMapperAdapter(new JacksonMapperAdapter()); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient() + }); + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, new Retrofit.Builder()) { }; + Response response = serviceClient.httpClient() .newCall(new Request.Builder().get().url("http://localhost").build()).execute(); Assert.assertEquals(200, response.code()); } @Test public void customUserAgentTests() throws Exception { - - RestClient.Builder restBuilder = new RestClient.Builder("http://localhost") - .withUserAgent("Awesome") - .withInterceptor(new Interceptor() { + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() + .addInterceptor(new UserAgentInterceptor().withUserAgent("Awesome")) + .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { String header = chain.request().header("User-Agent"); @@ -58,10 +57,9 @@ public Response intercept(Chain chain) throws IOException { .protocol(Protocol.HTTP_1_1) .build(); } - }) - .withMapperAdapter(new JacksonMapperAdapter()); - ServiceClient serviceClient = new ServiceClient(restBuilder.build()) { }; - Response response = serviceClient.restClient().httpClient() + }); + ServiceClient serviceClient = new ServiceClient("http://localhost", clientBuilder, new Retrofit.Builder()) { }; + Response response = serviceClient.httpClient() .newCall(new Request.Builder().get().url("http://localhost").build()).execute(); Assert.assertEquals(200, response.code()); }