com.github.davidmoten.microsoft.client.builder.MicrosoftClientBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of odata-client-microsoft-client-builder Show documentation
Show all versions of odata-client-microsoft-client-builder Show documentation
Builds client for Microsoft Graph 1.0 and Beta, includes MsGraph authentication support
package com.github.davidmoten.microsoft.client.builder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.SocketConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.github.davidmoten.guavamini.Preconditions;
import com.github.davidmoten.microsoft.authentication.AccessTokenProvider;
import com.github.davidmoten.microsoft.authentication.AuthenticationEndpoint;
import com.github.davidmoten.microsoft.authentication.Authenticator;
import com.github.davidmoten.microsoft.authentication.BearerAuthenticator;
import com.github.davidmoten.microsoft.authentication.ClientCredentialsAccessTokenProvider;
import com.github.davidmoten.odata.client.Context;
import com.github.davidmoten.odata.client.HttpService;
import com.github.davidmoten.odata.client.Path;
import com.github.davidmoten.odata.client.PathStyle;
import com.github.davidmoten.odata.client.Properties;
import com.github.davidmoten.odata.client.RequestHeader;
import com.github.davidmoten.odata.client.SchemaInfo;
import com.github.davidmoten.odata.client.Serializer;
import com.github.davidmoten.odata.client.internal.ApacheHttpClientHttpService;
public final class MicrosoftClientBuilder {
private final Creator creator;
private final String baseUrl;
private String tenantName;
private String resource;
private List scopes = new ArrayList<>();
private String clientId;
private String clientSecret;
private long refreshBeforeExpiryDurationMs = TimeUnit.MINUTES.toMillis(5);
private long connectTimeoutMs;
private long readTimeoutMs;
private Optional proxyHost = Optional.empty();
private Optional proxyPort = Optional.empty();
private Optional proxyUsername = Optional.empty();
private Optional proxyPassword = Optional.empty();
private Optional> httpClientSupplier = Optional.empty();
private Optional> httpClientBuilderExtras = Optional
.empty();
private String authenticationEndpoint = AuthenticationEndpoint.GLOBAL.url();
private Function super HttpService, ? extends HttpService> httpServiceTransformer = x -> x;
private Optional accessTokenProvider = Optional.empty();
private Optional authenticator = Optional.empty();
private Optional> basicCredentials = Optional.empty();
private final List schemas;
private final PathStyle pathStyle;
MicrosoftClientBuilder(String baseUrl, Creator creator, List schemas, PathStyle pathStyle) {
Preconditions.checkNotNull(baseUrl);
Preconditions.checkNotNull(creator);
this.baseUrl = baseUrl;
this.creator = creator;
this.schemas = schemas;
this.pathStyle = pathStyle;
}
public static BuilderBuilder baseUrl(String baseUrl) {
Preconditions.checkNotNull(baseUrl);
return new BuilderBuilder(baseUrl);
}
public static final class BuilderBuilder {
private final String baseUrl;
BuilderBuilder(String baseUrl) {
this.baseUrl = baseUrl;
}
public BuilderBuilder2 creator(Creator creator) {
return new BuilderBuilder2(this, creator);
}
}
public static final class BuilderBuilder2 {
private final BuilderBuilder b;
private Creator creator;
private final List schemas = new ArrayList<>();
private PathStyle pathStyle = PathStyle.IDENTIFIERS_AS_SEGMENTS;
BuilderBuilder2(BuilderBuilder b, Creator creator) {
this.b = b;
this.creator = creator;
}
public BuilderBuilder2 addSchema(SchemaInfo schema) {
schemas.add(schema);
return this;
}
/**
* Sets the path style. Default is {@link PathStyle#IDENTIFIERS_AS_SEGMENTS}.
* @param pathStyle path style to use
* @return this
*/
public BuilderBuilder2 pathStyle(PathStyle pathStyle) {
this.pathStyle = pathStyle;
return this;
}
public MicrosoftClientBuilder build() {
return new MicrosoftClientBuilder(b.baseUrl,creator, schemas, pathStyle);
}
}
public BuilderCustomAuthenticator authenticator(Authenticator authenticator) {
return new BuilderCustomAuthenticator(this, authenticator);
}
public static final class BuilderCustomAuthenticator {
private final Authenticator authenticator;
private final MicrosoftClientBuilder b;
BuilderCustomAuthenticator(MicrosoftClientBuilder b, Authenticator authenticator) {
this.authenticator = authenticator;
this.b = b;
}
public BuilderCustomAuthenticator connectTimeout(long duration, TimeUnit unit) {
b.connectTimeoutMs = unit.toMillis(duration);
return this;
}
public BuilderCustomAuthenticator readTimeout(long duration, TimeUnit unit) {
b.readTimeoutMs = unit.toMillis(duration);
return this;
}
public BuilderCustomAuthenticator proxyHost(String proxyHost) {
b.proxyHost = Optional.of(proxyHost);
return this;
}
public BuilderCustomAuthenticator proxyPort(int proxyPort) {
b.proxyPort = Optional.of(proxyPort);
return this;
}
public BuilderCustomAuthenticator proxyUsername(String username) {
b.proxyUsername = Optional.of(username);
return this;
}
public BuilderCustomAuthenticator proxyPassword(String password) {
b.proxyPassword = Optional.of(password);
return this;
}
/**
* Do your own thing to create an Apache {@link HttpClient}. This method might
* disappear if the underlying http service gets swapped out for another one.
* You might want to use this method if your proxy interaction is complicated
* for example.
*
* @param supplier provider of HttpClient
* @return this
*/
public BuilderCustomAuthenticator httpClientProvider(
Supplier supplier) {
Preconditions.checkArgument(!b.httpClientBuilderExtras.isPresent());
b.httpClientSupplier = Optional.of(supplier);
return this;
}
/**
* Do your own thing to further modify a configured {@link HttpClientBuilder}.
* This method might disappear if the underlying http service gets swapped out
* for another one. You might want to use this method if your proxy interaction
* is complicated for example or if you want to use interceptors or other fancy
* stuff.
*
* @param extras modifier of builder
* @return this
*/
public BuilderCustomAuthenticator httpClientBuilderExtras(
Function extras) {
Preconditions.checkArgument(!b.httpClientSupplier.isPresent());
b.httpClientBuilderExtras = Optional.of(extras);
return this;
}
public T build() {
return createService(b.baseUrl, authenticator, b.connectTimeoutMs, b.readTimeoutMs,
b.proxyHost, b.proxyPort, b.proxyUsername, b.proxyPassword,
b.httpClientSupplier, b.httpClientBuilderExtras, b.creator,
b.authenticationEndpoint, b.httpServiceTransformer,b.schemas, b.pathStyle);
}
}
public Builder5 basicAuthentication(Supplier usernamePassword) {
this.basicCredentials = Optional.of(usernamePassword);
return new Builder5(this);
}
public Builder tenantName(String tenantName) {
this.tenantName = tenantName;
return new Builder(this);
}
public static final class Builder {
private final MicrosoftClientBuilder b;
Builder(MicrosoftClientBuilder b) {
this.b = b;
}
public Builder2 resource(String resource) {
Preconditions.checkNotNull(resource);
b.resource = resource;
return new Builder2(b);
}
}
public static final class Builder2 {
private final MicrosoftClientBuilder b;
Builder2(MicrosoftClientBuilder b) {
this.b = b;
}
public Builder3 scope(String... scopes) {
Preconditions.checkNotNull(scopes);
return scope(Arrays.asList(scopes));
}
public Builder3 scope(List scopes) {
Preconditions.checkNotNull(scopes);
b.scopes.addAll(scopes);
return new Builder3(b);
}
public Builder4 clientId(String clientId) {
return new Builder3(b).clientId(clientId);
}
}
public static final class Builder3 {
private final MicrosoftClientBuilder b;
Builder3(MicrosoftClientBuilder b) {
this.b = b;
}
public Builder4 clientId(String clientId) {
b.clientId = clientId;
return new Builder4(b);
}
}
public static final class Builder4 {
private final MicrosoftClientBuilder b;
Builder4(MicrosoftClientBuilder b) {
this.b = b;
}
public Builder5 clientSecret(String clientSecret) {
b.clientSecret = clientSecret;
return new Builder5(b);
}
}
public static final class Builder5 {
private final MicrosoftClientBuilder b;
Builder5(MicrosoftClientBuilder b) {
this.b = b;
}
public Builder5 refreshBeforeExpiry(long duration, TimeUnit unit) {
b.refreshBeforeExpiryDurationMs = unit.toMillis(duration);
return this;
}
public Builder5 connectTimeout(long duration, TimeUnit unit) {
b.connectTimeoutMs = unit.toMillis(duration);
return this;
}
public Builder5 readTimeout(long duration, TimeUnit unit) {
b.readTimeoutMs = unit.toMillis(duration);
return this;
}
public Builder5 proxyHost(String proxyHost) {
b.proxyHost = Optional.of(proxyHost);
return this;
}
public Builder5 proxyPort(int proxyPort) {
b.proxyPort = Optional.of(proxyPort);
return this;
}
public Builder5 httpServiceTransformer(
Function super HttpService, ? extends HttpService> transformer) {
b.httpServiceTransformer = transformer;
return this;
}
public Builder5 accessTokenProvider(AccessTokenProvider atp) {
b.accessTokenProvider = Optional.of(atp);
return this;
}
public Builder5 proxyUsername(String username) {
b.proxyUsername = Optional.of(username);
return this;
}
public Builder5 proxyPassword(String password) {
b.proxyPassword = Optional.of(password);
return this;
}
/**
* Do your own thing to create an Apache {@link HttpClient}. This method might
* disappear if the underlying http service gets swapped out for another one.
* You might want to use this method if your proxy interaction is complicated
* for example.
*
* @param supplier provider of HttpClient
* @return this
*/
public Builder5 httpClientProvider(Supplier supplier) {
Preconditions.checkArgument(!b.httpClientBuilderExtras.isPresent());
b.httpClientSupplier = Optional.of(supplier);
return this;
}
/**
* Do your own thing to further modify a configured {@link HttpClientBuilder}.
* This method might disappear if the underlying http service gets swapped out
* for another one. You might want to use this method if your proxy interaction
* is complicated for example or if you want to use interceptors or other fancy
* stuff.
*
* @param extras modifier of builder
* @return this
*/
public Builder5 httpClientBuilderExtras(
Function extras) {
Preconditions.checkArgument(!b.httpClientSupplier.isPresent());
b.httpClientBuilderExtras = Optional.of(extras);
return this;
}
/**
* Sets the authentication endpoint url to use for access tokens etc. If not
* specified defaults to {@link AuthenticationEndpoint#GLOBAL}.
*
* @param authenticationEndpoint endpoint to use for authentication
* @return this
*/
public Builder5 authenticationEndpoint(AuthenticationEndpoint authenticationEndpoint) {
return authenticationEndpoint(authenticationEndpoint.url());
}
/**
* Sets the authentication endpoint url to use for access tokens etc. If not
* specified defaults to {@link AuthenticationEndpoint#GLOBAL} url.
*
* @param authenticationEndpoint endpoint to use for authentication
* @return this
*/
public Builder5 authenticationEndpoint(String authenticationEndpoint) {
b.authenticationEndpoint = authenticationEndpoint;
return this;
}
public Builder5 authenticator(Authenticator authenticator) {
b.authenticator = Optional.of(authenticator);
return this;
}
public T build() {
if (!b.authenticator.isPresent() && b.basicCredentials.isPresent()) {
Supplier bc = b.basicCredentials.get();
authenticator((url, requestHeaders) -> {
// some streaming endpoints object to auth so don't add header
// if not on the base service
if (url.toExternalForm().startsWith(b.baseUrl)) {
// remove Authorization header if present
List list = requestHeaders //
.stream() //
.filter(rh -> !rh.name().equalsIgnoreCase("Authorization")) //
.collect(Collectors.toList());
// add basic auth request header
UsernamePassword c = bc.get();
list.add(basicAuth(c.username(), c.password()));
return list;
} else {
return requestHeaders;
}
});
}
return createService(b.baseUrl, b.tenantName, b.resource, b.scopes, b.clientId,
b.clientSecret, b.refreshBeforeExpiryDurationMs, b.connectTimeoutMs,
b.readTimeoutMs, b.proxyHost, b.proxyPort, b.proxyUsername, b.proxyPassword,
b.httpClientSupplier, b.httpClientBuilderExtras, b.creator,
b.authenticationEndpoint, b.httpServiceTransformer, b.accessTokenProvider,
b.authenticator, b.schemas, b.pathStyle);
}
}
private static RequestHeader basicAuth(String username, String password) {
String s = username + ":" + password;
String encoded = Base64.getEncoder().encodeToString(s.getBytes(StandardCharsets.UTF_8));
return RequestHeader.create("Authorization", "Basic " + encoded);
}
public static final class UsernamePassword {
private final String username;
private final String password;
UsernamePassword(String username, String password) {
this.username = username;
this.password = password;
}
public static UsernamePassword create(String username, String password) {
return new UsernamePassword(username, password);
}
public String username() {
return username;
}
public String password() {
return password;
}
}
private static T createService(String baseUrl, String tenantName, String resource,
List scopes, String clientId, String clientSecret, long refreshBeforeExpiryDurationMs,
long connectTimeoutMs, long readTimeoutMs, //
Optional proxyHost, Optional proxyPort, //
Optional proxyUsername, Optional proxyPassword,
Optional> supplier,
Optional> httpClientBuilderExtras,
Creator creator, //
String authenticationEndpoint, //
Function super HttpService, ? extends HttpService> httpServiceTransformer,
Optional accessTokenProviderOverride, //
Optional authenticator, List schemas, PathStyle pathStyle) {
final Authenticator auth;
if (authenticator.isPresent()) {
auth = authenticator.get();
} else {
AccessTokenProvider accessTokenProvider = accessTokenProviderOverride //
.orElseGet(() -> ClientCredentialsAccessTokenProvider //
.tenantName(tenantName) //
.resource(resource) //
.scope(scopes) //
.clientId(clientId) //
.clientSecret(clientSecret) //
.connectTimeoutMs(connectTimeoutMs, TimeUnit.MILLISECONDS) //
.readTimeoutMs(readTimeoutMs, TimeUnit.MILLISECONDS) //
.refreshBeforeExpiry(refreshBeforeExpiryDurationMs,
TimeUnit.MILLISECONDS) //
.authenticationEndpoint(authenticationEndpoint) //
.proxyHost(proxyHost) //
.proxyPort(proxyPort) //
.proxyUsername(proxyUsername) //
.proxyPassword(proxyPassword) //
.build());
auth = new BearerAuthenticator(accessTokenProvider, baseUrl);
}
return createService(baseUrl, auth, connectTimeoutMs, readTimeoutMs, proxyHost, proxyPort,
proxyUsername, proxyPassword, supplier, httpClientBuilderExtras, creator,
authenticationEndpoint, httpServiceTransformer, schemas, pathStyle);
}
private static Supplier createClientSupplier(long connectTimeoutMs,
long readTimeoutMs, Optional proxyHost, Optional proxyPort,
Optional proxyUsername, Optional proxyPassword,
Optional> supplier,
Optional> httpClientBuilderExtras) {
final Supplier clientSupplier;
if (supplier.isPresent()) {
clientSupplier = supplier.get();
} else {
clientSupplier = () -> createHttpClient(connectTimeoutMs, readTimeoutMs, proxyHost,
proxyPort, proxyUsername, proxyPassword, httpClientBuilderExtras);
}
return clientSupplier;
}
@SuppressWarnings("resource")
private static T createService(String baseUrl, Authenticator authenticator,
long connectTimeoutMs, long readTimeoutMs, //
Optional proxyHost, Optional proxyPort, //
Optional proxyUsername, Optional proxyPassword,
Optional> supplier,
Optional> httpClientBuilderExtras,
Creator creator, String authenticationEndpoint, //
Function super HttpService, ? extends HttpService> httpServiceTransformer, //
List schemas, PathStyle pathStyle) {
final Supplier clientSupplier = createClientSupplier(connectTimeoutMs,
readTimeoutMs, proxyHost, proxyPort, proxyUsername, proxyPassword, supplier,
httpClientBuilderExtras);
Path basePath = new Path(baseUrl, pathStyle);
HttpService httpService = new ApacheHttpClientHttpService( //
basePath, //
clientSupplier, //
authenticator::authenticate);
httpService = httpServiceTransformer.apply(httpService);
return creator.create(new Context(Serializer.INSTANCE, httpService, createProperties(), schemas));
}
public static Map createProperties() {
Map p = new HashMap<>();
p.put(Properties.MODIFY_STREAM_EDIT_LINK, "true");
p.put(Properties.ATTEMPT_STREAM_WHEN_NO_METADATA, "true");
p.put(Properties.ACTION_OR_FUNCTION_SEGMENT_SIMPLE_NAME, "true");
return p;
}
private static CloseableHttpClient createHttpClient(long connectTimeoutMs, long readTimeoutMs,
Optional proxyHost, Optional proxyPort, Optional proxyUsername,
Optional proxyPassword,
Optional> httpClientBuilderExtras) {
RequestConfig config = RequestConfig.custom() //
.setConnectTimeout((int) connectTimeoutMs) //
.setSocketTimeout((int) readTimeoutMs) //
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Set soTimeout here to affect socketRead in the phase of ssl handshake. Note
// that
// the RequestConfig.setSocketTimeout will take effect only after the ssl
// handshake completed.
cm.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout((int) readTimeoutMs).build());
HttpClientBuilder b = HttpClientBuilder //
.create() //
.useSystemProperties() //
.setDefaultRequestConfig(config) //
.setConnectionManager(cm);
if (proxyHost.isPresent()) {
HttpHost proxy = new HttpHost(proxyHost.get(), proxyPort.get());
if (proxyUsername.isPresent()) {
Credentials credentials = new UsernamePasswordCredentials(proxyUsername.get(),
proxyPassword.orElse(null));
AuthScope authScope = new AuthScope(proxyHost.get(), proxyPort.get());
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(authScope, credentials);
b = b.setDefaultCredentialsProvider(credentialsProvider);
}
b = b.setProxy(proxy);
}
if (httpClientBuilderExtras.isPresent()) {
b = httpClientBuilderExtras.get().apply(b);
}
return b.build();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy