All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.java.com.cloudant.client.api.ClientBuilder Maven / Gradle / Ivy

There is a newer version: 2.20.1
Show newest version
/*
 * Copyright © 2015, 2020 IBM Corp. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language governing permissions
 * and limitations under the License.
 */

package com.cloudant.client.api;

import com.cloudant.client.api.views.Key;
import com.cloudant.client.internal.util.CloudFoundryService;
import com.cloudant.client.internal.util.DeserializationTypes;
import com.cloudant.client.internal.util.IndexDeserializer;
import com.cloudant.client.internal.util.SecurityDeserializer;
import com.cloudant.client.internal.util.ShardDeserializer;
import com.cloudant.client.org.lightcouch.CouchDbException;
import com.cloudant.client.org.lightcouch.CouchDbProperties;
import com.cloudant.client.org.lightcouch.internal.CouchDbUtil;
import com.cloudant.http.HttpConnectionInterceptor;
import com.cloudant.http.HttpConnectionRequestInterceptor;
import com.cloudant.http.HttpConnectionResponseInterceptor;
import com.cloudant.http.internal.interceptors.CookieInterceptor;
import com.cloudant.http.internal.interceptors.IamCookieInterceptor;
import com.cloudant.http.internal.interceptors.IamServerBasicAuthInterceptor;
import com.cloudant.http.internal.interceptors.ProxyAuthInterceptor;
import com.cloudant.http.internal.interceptors.SSLCustomizerInterceptor;
import com.cloudant.http.internal.interceptors.TimeoutCustomizationInterceptor;
import com.cloudant.http.internal.interceptors.UserAgentInterceptor;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.io.UnsupportedEncodingException;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLDecoder;
import java.security.Security;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import javax.net.ssl.SSLSocketFactory;

/**
 * This class builds new {@link CloudantClient} instances.
 *
 * 

Create a new CloudantClient instance for a Cloudant account

*
 * {@code
 * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
 *                          .username("yourUsername")
 *                          .password("yourPassword")
 *                          .build();
 * }
 * 
* *

Create a new CloudantClient instance for a Cloudant Bluemix instance

*
 * {@code
 * CloudantClient client = ClientBuilder.bluemix(System.getenv("VCAP_SERVICES")).build();
 * }
 * 
* *

Create a new CloudantClient instance for a Cloudant Local

*
 * {@code
 * CloudantClient client = ClientBuilder.url(new URL("https://yourCloudantLocalAddress.example"))
 *                          .username("yourUsername")
 *                          .password("yourPassword")
 *                          .build();
 * }
 * 
* *

Examples creating instances with additional options

*

Configure a proxy server

*
 * {@code
 * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
 *                          .username("yourUsername")
 *                          .password("yourPassword")
 *                          .proxyURL(new URL("https://yourProxyServerAddress.example"))
 *                          .proxyUser(yourProxyUser)
 *                          .proxyPassword(yourProxyPass)
 *                          .build();
 * }
 * 
* *

Client with a custom SSL socket factory

*
 * {@code
 * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
 *                          .username("yourUsername")
 *                          .password("yourPassword")
 *                          .customSSLSocketFactory(...)
 *                          .build();
 * }
 * 
* *

Client with custom connection and read timeouts

*
 * {@code
 * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
 *                          .username("yourUsername")
 *                          .password("yourPassword")
 *                          .connectTimeout(1, TimeUnit.MINUTES)
 *                          .readTimeout(1, TimeUnit.MINUTES)
 *                          .build();
 * }
 * 
* * @since 2.0.0 */ public class ClientBuilder { private static final UserAgentInterceptor USER_AGENT_INTERCEPTOR = new UserAgentInterceptor(ClientBuilder.class.getClassLoader(), "META-INF/com.cloudant.client.properties"); /** * Default max of 6 connections **/ public static final int DEFAULT_MAX_CONNECTIONS = 6; /** * Connection timeout defaults to 5 minutes **/ public static final long DEFAULT_CONNECTION_TIMEOUT = 5l; /** * Read timeout defaults to 5 minutes **/ public static final long DEFAULT_READ_TIMEOUT = 5l; private static final Logger logger = Logger.getLogger(ClientBuilder.class.getName()); private List requestInterceptors = new ArrayList (); private List responseInterceptors = new ArrayList (); private String password; private String username; private URL url; private GsonBuilder gsonBuilder; /** * Defaults to {@link #DEFAULT_MAX_CONNECTIONS} **/ private int maxConnections = DEFAULT_MAX_CONNECTIONS; private URL proxyURL; private String proxyUser; private String proxyPassword; private boolean isSSLAuthenticationDisabled; private SSLSocketFactory authenticatedModeSSLSocketFactory; private long connectTimeout = DEFAULT_CONNECTION_TIMEOUT; private TimeUnit connectTimeoutUnit = TimeUnit.MINUTES; private long readTimeout = DEFAULT_READ_TIMEOUT; private TimeUnit readTimeoutUnit = TimeUnit.MINUTES; private String iamApiKey; private String iamServerClientId; private String iamServerClientSecret; /** * Constructs a new ClientBuilder for building a CloudantClient instance to connect to the * Cloudant server with the specified account. * * @param account the Cloudant account name to connect to e.g. "example" is the account name * for the "example.cloudant.com" endpoint * @return a new ClientBuilder for the account * @throws IllegalArgumentException if the specified account name forms an invalid endpoint URL */ public static ClientBuilder account(String account) { logger.config("Account: " + account); return ClientBuilder.url( convertStringToURL(String.format("https://%s.cloudant.com", account))); } /** * Constructs a new ClientBuilder for building a CloudantClient instance to connect to the * Cloudant server with the specified URL. * * @param url server URL e.g. "https://yourCloudantLocalAddress.example" * @return a new ClientBuilder for the account */ public static ClientBuilder url(URL url) { CouchDbUtil.assertNotNull(url, "Cloudant URL"); return new ClientBuilder(url); } private ClientBuilder(URL url) { logger.config("URL: " + url); String urlProtocol = url.getProtocol(); String urlHost = url.getHost(); //Check if port exists int urlPort = url.getPort(); if (urlPort < 0) { urlPort = url.getDefaultPort(); } if (url.getUserInfo() != null) { //Get username and password and replace credential variables try { this.username = URLDecoder.decode(url.getUserInfo().substring(0, url .getUserInfo() .indexOf(":")), "UTF-8"); this.password = URLDecoder.decode(url.getUserInfo().substring(url .getUserInfo() .indexOf(":") + 1), "UTF-8"); } catch (UnsupportedEncodingException e) { // Should never happen UTF-8 is required in JVM throw new RuntimeException(e); } } // Check if a path exists and sanitize it by removing whitespace and any trailing / String urlPath = url.getPath().trim(); urlPath = urlPath.endsWith("/") ? urlPath.substring(0, urlPath.length() - 1) : urlPath; // Reconstruct URL without user credentials this.url = convertStringToURL(urlProtocol + "://" + urlHost + ":" + urlPort + urlPath); } /** * Build the {@link CloudantClient} instance based on the endpoint used to construct this * client builder and the options that have been set on it before calling this method. * * @return the {@link CloudantClient} instance for the specified end point and options */ public CloudantClient build() { logger.config("Building client using URL: " + url); //Build properties and couchdb client CouchDbProperties props = new CouchDbProperties(url); props.addRequestInterceptors(USER_AGENT_INTERCEPTOR); if (this.iamApiKey != null) { // Create IAM cookie interceptor and set in HttpConnection interceptors IamCookieInterceptor cookieInterceptor = new IamCookieInterceptor(this.iamApiKey, this.url.toString()); props.addRequestInterceptors(cookieInterceptor); props.addResponseInterceptors(cookieInterceptor); logger.config("Added IAM cookie interceptor"); if (this.iamServerClientId != null && this.iamServerClientSecret != null) { props.addRequestInterceptors(new IamServerBasicAuthInterceptor( cookieInterceptor.getIamServerUrl(), iamServerClientId, iamServerClientSecret)); } } //Create cookie interceptor else if (this.username != null && this.password != null) { //make interceptor if both username and password are not null //Create cookie interceptor and set in HttpConnection interceptors CookieInterceptor cookieInterceptor = new CookieInterceptor(username, password, this.url.toString()); props.addRequestInterceptors(cookieInterceptor); props.addResponseInterceptors(cookieInterceptor); logger.config("Added cookie interceptor"); } else { //If username or password is null, throw an exception if (username != null || password != null) { //Username and password both have to contain values throw new CouchDbException("Either a username and password must be provided, or " + "both values must be null. Please check the credentials and try again."); } } //If setter methods for read and connection timeout are not called, default values // are used. logger.config(String.format("Connect timeout: %s %s", connectTimeout, connectTimeoutUnit)); logger.config(String.format("Read timeout: %s %s", readTimeout, readTimeoutUnit)); // Log a warning if the DNS cache time is too long try { boolean shouldLogValueWarning = false; boolean isUsingDefaultTTLValue = true; String ttlString = Security.getProperty("networkaddress.cache.ttl"); // Was able to access the property if (ttlString != null) { try { int ttl = Integer.parseInt(ttlString); isUsingDefaultTTLValue = false; logger.finest("networkaddress.cache.ttl was " + ttl); if (ttl > 30 || ttl < 0) { shouldLogValueWarning = true; } } catch (NumberFormatException nfe) { // Suppress the exception, this will result in the default being used logger.finest("networkaddress.cache.ttl was not an int."); } } if (isUsingDefaultTTLValue && System.getSecurityManager() != null) { //If we're using a default value and there is a SecurityManager we need to warn shouldLogValueWarning = true; } if (shouldLogValueWarning) { logger.warning("DNS cache lifetime may be too long. DNS cache lifetimes in excess" + " of 30 seconds may impede client operation during cluster failover."); } } catch (SecurityException e) { // Couldn't access the property; log a warning logger.warning("Permission denied to check Java DNS cache TTL. If the cache " + "lifetime is too long cluster failover will be impeded."); } props.addRequestInterceptors(new TimeoutCustomizationInterceptor(connectTimeout, connectTimeoutUnit, readTimeout, readTimeoutUnit)); //Set connect options props.setMaxConnections(maxConnections); props.setProxyURL(proxyURL); if (proxyUser != null) { //if there was proxy auth information set up proxy auth if ("http".equals(url.getProtocol())) { // If we are using http, create an interceptor to add the Proxy-Authorization header props.addRequestInterceptors(new ProxyAuthInterceptor(proxyUser, proxyPassword)); logger.config("Added proxy auth interceptor"); } else { // Set up an authenticator props.setProxyAuthentication(new PasswordAuthentication(proxyUser, proxyPassword.toCharArray())); } } if (isSSLAuthenticationDisabled) { props.addRequestInterceptors(SSLCustomizerInterceptor .SSL_AUTH_DISABLED_INTERCEPTOR); logger.config("SSL authentication is disabled"); } if (authenticatedModeSSLSocketFactory != null) { props.addRequestInterceptors(new SSLCustomizerInterceptor( authenticatedModeSSLSocketFactory )); logger.config("Added custom SSL socket factory"); } //Set http connection interceptors if (requestInterceptors != null) { for (HttpConnectionRequestInterceptor requestInterceptor : requestInterceptors) { props.addRequestInterceptors(requestInterceptor); logger.config("Added request interceptor: " + requestInterceptor.getClass() .getName()); } } if (responseInterceptors != null) { for (HttpConnectionResponseInterceptor responseInterceptor : responseInterceptors) { props.addResponseInterceptors(responseInterceptor); logger.config("Added response interceptor: " + responseInterceptor.getClass() .getName()); } } //if no gsonBuilder has been provided, create a new one if (gsonBuilder == null) { gsonBuilder = new GsonBuilder(); logger.config("Using default GSON builder"); } else { logger.config("Using custom GSON builder"); } //always register additional TypeAdapaters for derserializing some Cloudant specific // types before constructing the CloudantClient gsonBuilder.registerTypeAdapter(DeserializationTypes.SHARDS, new ShardDeserializer()) .registerTypeAdapter(DeserializationTypes.INDICES, new IndexDeserializer()) .registerTypeAdapter(DeserializationTypes.PERMISSIONS_MAP, new SecurityDeserializer()) .registerTypeAdapter(Key.ComplexKey.class, new Key.ComplexKeyDeserializer()); return new CloudantClient(props, gsonBuilder); } /** * Sets a username or API key for the client connection. * * @param username the user or API key for the session * @return this ClientBuilder object for setting additional options */ public ClientBuilder username(String username) { this.username = username; return this; } /** * Sets the password for the client connection. The password is the one for the username or * API key set by the {@link #username(String)} method. * * @param password user password or API key passphrase * @return this ClientBuilder object for setting additional options */ public ClientBuilder password(String password) { this.password = password; return this; } /** * Set a custom GsonBuilder to use when serializing and de-serializing JSON in requests and * responses between the CloudantClient and the server. *

* Note: the supplied GsonBuilder will be augmented with some internal TypeAdapters. *

* * @param gsonBuilder the custom GsonBuilder to use * @return this ClientBuilder object for setting additional options */ public ClientBuilder gsonBuilder(GsonBuilder gsonBuilder) { this.gsonBuilder = gsonBuilder; return this; } /** * Set the maximum number of connections to maintain in the connection pool. *

* Note: this setting only applies if using the optional OkHttp dependency. If OkHttp is not * present then the JVM configuration is used for pooling. Consult the JVM documentation for * the {@code http.maxConnections} property for further details. *

* Defaults to {@link #DEFAULT_MAX_CONNECTIONS} * * @param maxConnections the maximum number of simultaneous connections to open to the server * @return this ClientBuilder object for setting additional options */ public ClientBuilder maxConnections(int maxConnections) { this.maxConnections = maxConnections; return this; } /** *

* Sets a proxy url for the client connection. *

*

* Note that this method can only set the configuration for an unencrypted HTTP proxy. * Even when using this type of proxy communication from the client to a https database server * is encrypted via a SSL tunnel. *

* * @param proxyURL the URL of the proxy server * @return this ClientBuilder object for setting additional options * @see Advanced configuration: Proxies */ public ClientBuilder proxyURL(URL proxyURL) { this.proxyURL = proxyURL; return this; } /** *

* Sets an optional proxy username for the client connection. *

*

* Note: Use {@link java.net.Authenticator#setDefault(Authenticator)} to configure proxy * authentication when using the JVM default HttpURLConnection (i.e. not using the optional * okhttp dependency) in combination with a HTTPS database server. *

* * @param proxyUser username for the proxy server * @return this ClientBuilder object for setting additional options * @see Advanced configuration: Proxies */ public ClientBuilder proxyUser(String proxyUser) { this.proxyUser = proxyUser; return this; } /** *

* Sets an optional proxy password for the proxy user specified by * {@link #proxyUser(String)}. *

*

* Note: Use {@link java.net.Authenticator#setDefault(Authenticator)} to configure proxy * authentication when using the JVM default HttpURLConnection (i.e. not using the optional * okhttp dependency) in combination with a HTTPS database server. *

* * @param proxyPassword password for the proxy server user * @return this ClientBuilder object for setting additional options * @see Advanced configuration: Proxies */ public ClientBuilder proxyPassword(String proxyPassword) { this.proxyPassword = proxyPassword; return this; } /** * Flag to disable hostname verification and certificate chain validation. This is not * recommended, but for example could be useful for testing with a self-signed certificate. *

* The SSL authentication is enabled by default meaning that hostname verification * and certificate chain validation is done using the JVM default settings. *

*

* Not supported with Java 8u252 or newer and the optional OkHttp dependency. *

* * @return this ClientBuilder object for setting additional options * @throws IllegalStateException if {@link #customSSLSocketFactory(SSLSocketFactory)} * has been called on this ClientBuilder * @see #customSSLSocketFactory(SSLSocketFactory) */ public ClientBuilder disableSSLAuthentication() { if (authenticatedModeSSLSocketFactory == null) { this.isSSLAuthenticationDisabled = true; } else { throw new IllegalStateException("Cannot disable SSL authentication when a " + "custom SSLSocketFactory has been set."); } return this; } /** * Specifies the custom SSLSocketFactory to use when connecting to Cloudant over a * https URL, when SSL authentication is enabled. *

* Not supported with Java 8u252 or newer and the optional OkHttp dependency. *

* * @param factory An SSLSocketFactory, or null for the * default SSLSocketFactory of the JRE. * @return this ClientBuilder object for setting additional options * @throws IllegalStateException if {@link #disableSSLAuthentication()} * has been called on this ClientBuilder * @see #disableSSLAuthentication() */ public ClientBuilder customSSLSocketFactory(SSLSocketFactory factory) { if (!isSSLAuthenticationDisabled) { this.authenticatedModeSSLSocketFactory = factory; } else { throw new IllegalStateException("Cannot use a custom SSLSocketFactory when " + "SSL authentication is disabled."); } return this; } /** * This method adds {@link HttpConnectionInterceptor}s to be used on the CloudantClient * connection. Interceptors can be used to modify the HTTP requests and responses between the * CloudantClient and the server. *

* An example interceptor use might be to apply a custom authorization mechanism. For * instance to use BasicAuth instead of CookieAuth it is possible to use a * {@link com.cloudant.http.interceptors.BasicAuthInterceptor} that adds the BasicAuth * {@code Authorization} header to the request: *

*
     * {@code
     * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
     *      .interceptors(new BasicAuthInterceptor("yourUsername:yourPassword"))
     *      .build()
     * }
     * 
* * @param interceptors one or more HttpConnectionInterceptor objects * @return this ClientBuilder object for setting additional options * @see HttpConnectionInterceptor */ public ClientBuilder interceptors(HttpConnectionInterceptor... interceptors) { for (HttpConnectionInterceptor interceptor : interceptors) { if (interceptor instanceof HttpConnectionRequestInterceptor) { requestInterceptors.add((HttpConnectionRequestInterceptor) interceptor); } if (interceptor instanceof HttpConnectionResponseInterceptor) { responseInterceptors.add((HttpConnectionResponseInterceptor) interceptor); } } return this; } /** * Sets the specified timeout value when opening the client connection. If the timeout * expires before the connection can be established, a * {@link java.net.SocketTimeoutException} is raised. *

* Example creating a {@link CloudantClient} with a connection timeout of 2 seconds: *

*
     * {@code
     * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
     *      .username("yourUsername")
     *      .password("yourPassword")
     *      .connectTimeout(2, TimeUnit.SECONDS)
     *      .build();
     * }
     * 
* Defaults to {@link #DEFAULT_CONNECTION_TIMEOUT} with {@link TimeUnit#MINUTES}. * * @param connectTimeout duration of the read timeout * @param connectTimeoutUnit unit of measurement of the read timeout parameter * @return this ClientBuilder object for setting additional options * @see java.net.HttpURLConnection#setConnectTimeout(int) **/ public ClientBuilder connectTimeout(long connectTimeout, TimeUnit connectTimeoutUnit) { this.connectTimeout = connectTimeout; this.connectTimeoutUnit = connectTimeoutUnit; return this; } /** * Sets the specified timeout value when reading from a {@link java.io.InputStream} with an * established client connection. If the timeout expires before there is data available for * read, a {@link java.net.SocketTimeoutException} is raised. *

* Example creating a {@link CloudantClient} with a read timeout of 2 seconds: *

*
     * {@code
     * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
     *      .username("yourUsername")
     *      .password("yourPassword")
     *      .readTimeout(2, TimeUnit.SECONDS)
     *      .build();
     * }
     * 
* Defaults to {@link #DEFAULT_READ_TIMEOUT} with {@link TimeUnit#MINUTES}. * * @param readTimeout duration of the read timeout * @param readTimeoutUnit unit of measurement of the read timeout parameter * @return this ClientBuilder object for setting additional options * @see java.net.HttpURLConnection#setReadTimeout(int) **/ public ClientBuilder readTimeout(long readTimeout, TimeUnit readTimeoutUnit) { this.readTimeout = readTimeout; this.readTimeoutUnit = readTimeoutUnit; return this; } /** * This is the same as calling {@link #bluemix(String, String)} with {@code instanceName} set to * {@code null}. * * @param vcapServices service information JSON string, for example the contents of * {@code VCAP_SERVICES} environment variable * @return a new ClientBuilder for the account * * @throws IllegalArgumentException see {@link #bluemix(String, String)} for conditions that * cause {@code IllegalArgumentException} to be thrown. */ public static ClientBuilder bluemix(String vcapServices) { return ClientBuilder.bluemix(vcapServices, null); } /** * Sets Cloudant client credentials by inspecting a service information JSON string. This object * takes the form of a {@code VCAP_SERVICES} environment variable which is a JSON object that * contains information that you can use to interact with a service instance in Bluemix. *

* Note: Specifying an instance name is only required when multiple Cloudant service instances * are present. If there is only a single Cloudant service instance then * {@link #bluemix(String)} can also be used. *

* * @param vcapServices service information JSON string, for example the contents of * {@code VCAP_SERVICES} environment variable * @param instanceName name of Bluemix service instance or {@code null} to try to use the only * available Cloudant service * @return a new ClientBuilder for the account * * @throws IllegalArgumentException if any of the following conditions are true: *
    *
  • The {@code vcapServices} is {@code null}.
  • *
  • The {@code vcapServices} is not valid.
  • *
  • A service with the name matching "cloudantNoSQLDB" could not be found in * {@code vcapServices}.
  • *
  • An instance with a name matching {@code instanceName} could not be found in * {@code vcapServices}.
  • *
  • The {@code instanceName} is {@code null} and multiple Cloudant service instances * exist in {@code vcapServices}.
  • *
*/ public static ClientBuilder bluemix(String vcapServices, String instanceName) { return bluemix(vcapServices, "cloudantNoSQLDB", instanceName); } /** * Sets Cloudant client credentials by inspecting a service information JSON string. This object * takes the form of a {@code VCAP_SERVICES} environment variable which is a JSON object that * contains information that you can use to interact with a service instance in Bluemix. * * @param vcapServices service information JSON string, for example the contents of * {@code VCAP_SERVICES} environment variable * @param serviceName name of Bluemix service to use * @param instanceName name of Bluemix service instance or {@code null} to try to use the only * available Cloudant service * @return a new ClientBuilder for the account * * @throws IllegalArgumentException if any of the following conditions are true: *
    *
  • The {@code vcapServices} is {@code null}.
  • *
  • The {@code serviceName} is {@code null}.
  • *
  • The {@code vcapServices} is not valid.
  • *
  • A service with the name matching {@code serviceName} could not be found in * {@code vcapServices}.
  • *
  • An instance with a name matching {@code instanceName} could not be found in * {@code vcapServices}.
  • *
  • The {@code instanceName} is {@code null} and multiple Cloudant service instances * exist in {@code vcapServices}.
  • *
*/ public static ClientBuilder bluemix(String vcapServices, String serviceName, String instanceName) { if (vcapServices == null) { throw new IllegalArgumentException("The vcapServices JSON information was null."); } if (serviceName == null) { throw new IllegalArgumentException("No Cloudant services information present."); } JsonObject obj; try { obj = (JsonObject) new JsonParser().parse(vcapServices); } catch (JsonParseException e) { throw new IllegalArgumentException("The vcapServices was not valid JSON.", e); } Gson gson = new GsonBuilder().create(); List cloudantServices = null; JsonElement service = obj.get(serviceName); if (service != null) { Type listType = new TypeToken>(){}.getType(); cloudantServices = gson.fromJson(service, listType); } if (cloudantServices == null || cloudantServices.size() == 0) { throw new IllegalArgumentException("No Cloudant services information present."); } if (instanceName == null) { if (cloudantServices.size() == 1) { CloudFoundryService cloudantService = cloudantServices.get(0); return vcapClientBuilder(cloudantService); } else { throw new IllegalArgumentException("Multiple Cloudant service instances present. " + "A service instance name must be specified."); } } for (CloudFoundryService cloudantService : cloudantServices) { if (instanceName.equals(cloudantService.name)) { return vcapClientBuilder(cloudantService); } } throw new IllegalArgumentException( String.format("Cloudant service instance matching name %s was not found.", instanceName) ); } private static ClientBuilder vcapClientBuilder(CloudFoundryService cloudantService) { // Create client with IAM if the API key exists if (cloudantService.credentials != null && cloudantService.credentials.host != null) { URL vcapUrl = convertStringToURL( String.format("https://%s", cloudantService.credentials.host)); ClientBuilder clientBuilder = ClientBuilder.url(vcapUrl); if (cloudantService.credentials.apikey != null) { return clientBuilder.iamApiKey(cloudantService.credentials.apikey); } else if (cloudantService.credentials.username != null && cloudantService.credentials.password != null) { return clientBuilder.username(cloudantService.credentials.username) .password(cloudantService.credentials.password); } else { throw new IllegalArgumentException( "The Cloudant service instance is missing the IAM API key, " + "or both the username and password credential properties."); } } else { throw new IllegalArgumentException( "The Cloudant service instance information was invalid."); } } /** * Sets the * IAM API key for the client connection. *

* Example creating a {@link CloudantClient} using IAM authentication: *

*
     * {@code
     * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
     *      .iamApiKey("yourIamApiKey")
     *      .build();
     * }
     * 
* * @param iamApiKey the IAM API key for the session * @return this ClientBuilder object for setting additional options */ public ClientBuilder iamApiKey(String iamApiKey) { this.iamApiKey = iamApiKey; return this; } /** * Sets the * IAM API key for the client connection. Also allows a client ID and secret * to be specified for use when authenticating with the IAM token server. *

* Example creating a {@link CloudantClient} using IAM authentication: *

*
     * {@code
     * CloudantClient client = ClientBuilder.account("yourCloudantAccount")
     *      .iamApiKey("yourIamApiKey", "yourClientId", "yourClientSecret")
     *      .build();
     * }
     * 
* * @param iamApiKey the IAM API key for the session * @param iamServerClientId Client ID used to authenticate with IAM token server * @param iamServerClientSecret Client secret used to authenticate with IAM token server * @return this ClientBuilder object for setting additional options */ public ClientBuilder iamApiKey(String iamApiKey, String iamServerClientId, String iamServerClientSecret) { this.iamApiKey = iamApiKey; this.iamServerClientId = iamServerClientId; this.iamServerClientSecret = iamServerClientSecret; return this; } private static URL convertStringToURL(String urlAsString) { try { return new URL(urlAsString); } catch (MalformedURLException e) { throw new RuntimeException(e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy