com.ibm.g11n.pipeline.client.ServiceAccount Maven / Gradle / Ivy
Show all versions of gp-java-client Show documentation
/*
* Copyright IBM Corp. 2015
*
* 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.ibm.g11n.pipeline.client;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.ibm.g11n.pipeline.client.rb.CloudResourceBundleControl;
import com.ibm.g11n.pipeline.iam.TokenManager;
import com.ibm.g11n.pipeline.iam.TokenManagerException;
import com.ibm.g11n.pipeline.iam.TokenManagerFactory;
/**
* ServiceAccount
is a class representing IBM Globalization Pipeline
* service account information, including service URL and credentials. An instance
* of ServiceAccount
is required to create an instance of
* {@link CloudResourceBundleControl}, which enables Java's {@link java.util.ResourceBundle}
* to access resources though IBM Globalization Pipelineservice.
*
* There are currently 3 factory methods available:
*
* - {@link ServiceAccount#getInstance()}: This method is recommended
* for an application running on Bluemix. The method loads an account configuration
* from environment variables and VCAP_SERVICES. If an instance of IBM Globalization
* Pipeline service is bound to a Bluemix application, then the configuration is
* automatically detected.
*
* - {@link ServiceAccount#getInstance(String, String, String, String)}: This method is
* recommended for an application running outside of Bluemix environment. You have
* to supply a valid service URL, service instance ID, user ID and password.
*
* - {@link ServiceAccount#getInstanceByVcapServices(String, String)}: This method
* might be used by an application running on Bluemix, when multiple IBM Globalization
* Pipeline service instances are bound to the application.
*
*
* @author Yoshito Umaoka
*/
public class ServiceAccount {
private static final Logger logger = Logger.getLogger(ServiceAccount.class.getName());
/**
* The environment variable name for specifying a service URL.
*/
public static final String GP_URL = "GP_URL";
/**
* The environment variable name for specifying an instance ID.
*/
public static final String GP_INSTANCE_ID = "GP_INSTANCE_ID";
/**
* The environment variable name for specifying a user ID.
*/
public static final String GP_USER_ID = "GP_USER_ID";
/**
* The environment variable name for specifying a password.
*/
public static final String GP_PASSWORD = "GP_PASSWORD";
/**
* The environment variable name for specifying a IAM API Key.
*/
public static final String GP_IAM_API_KEY = "GP_IAM_API_KEY";
/**
* The environment variable name for specifying a IAM bearer token.
*/
public static final String GP_IAM_BEARER_TOKEN = "GP_IAM_BEARER_TOKEN";
/**
* The environment variable name for specifying IAM endpoint.
*/
public static final String GP_IAM_ENDPOINT = "GP_IAM_ENDPOINT";
/**
* The environment variable name for specifying a service name used
* by Globalization Pipeline service. The value is used for searching
* valid credentials in VCAP_SERVICES. If this environment variable
* is not defined, the default name pattern ("gp-*" or "g11n-pipeline*")
* is used for look up.
*/
public static final String GP_SERVICE_NAME = "GP_SERVICE_NAME";
/**
* The environment variable name for specifying a service instance
* name used by an instance of Globalization Pipeline service.
* The value is used for searching valid credentials in VCAP_SERVICES.
* If this environment variable is not defined, the first service
* instance found in VCAP_SERVICES will be used.
*/
public static final String GP_SERVICE_INSTANCE_NAME = "GP_SERVICE_INSTANCE_NAME";
/**
* Default service name pattern used for locating Globalization Pipeline service
* instances.
*/
private static final Pattern GP_SERVICE_NAME_PATTERN = Pattern.compile("gp-.+|g11n-pipeline.*");
private String url; // No trailing '/'
private String instanceId;
private String userId;
private String password;
private TokenManager tokenManager;
/**
* Private constructor.
*
* @param url Service URL, no trailing '/'
* @param instanceId Service instance ID
* @param userId User ID
* @param password Password
*/
private ServiceAccount(String url, String instanceId, String userId, String password) {
this.url = Objects.requireNonNull(url, "url must not be null");
this.instanceId = Objects.requireNonNull(instanceId, "instanceId must not be null");
this.userId = Objects.requireNonNull(userId, "userId must not be null");
this.password = Objects.requireNonNull(password, "password mut not be null");
}
/**
* Private constructor.
*
* @param url
* Service URL, no trailing '/'
* @param instanceId
* Service instance ID
* @param tokenManager
* IAM token manager
*/
private ServiceAccount(String url, String instanceId, TokenManager tokenManager) {
this.url = Objects.requireNonNull(url, "url must not be null");
this.instanceId = Objects.requireNonNull(instanceId, "instanceId must not be null");
this.tokenManager = Objects.requireNonNull(tokenManager, "tokenManager must not be null");
}
/**
* Returns an instance of ServiceAccount for the specified IBM Globalization
* Pipeline service URL and credentials.
*
* All arguments must not be null.
*
* @param url The service URL of Globlization Pipeline service.
* (e.g. https://gp-rest.ng.bluemix.net/translate/rest)
* @param instanceId The instance ID of the service instance.
* (e.g. d3f537cd617f34c86ac6b270f3065e73)
* @param userId The user ID for the service instance.
* (e.g. e92a1282a0e4f97bec93aa9f56fdb838)
* @param password The password for the service instance.
* (e.g. zg5SlD+ftXYRIZDblLgEA/ILkkCNqE1y)
* @return An instance of ServiceAccount
*/
public static ServiceAccount getInstance(String url, String instanceId,
String userId, String password) {
if (url.endsWith("/")) {
// trim off trailing slash
url = url.substring(0, url.length() - 1);
}
return new ServiceAccount(url, instanceId, userId, password);
}
/**
* Returns an instance of ServiceAccount for the specified IBM Globalization
* Pipeline service URL and credentials.
*
* All arguments must no be null.
*
* @param url
* The service URL of Globlization Pipeline service. (e.g.
* https://gp-rest.ng.bluemix.net/translate/rest)
* @param instanceId
* The instance ID of the service instance. (e.g.
* d3f537cd617f34c86ac6b270f3065e73)
* @param tokenManager
* IAM Token Manager.
*
* @return An instance of ServiceAccount
*/
public static ServiceAccount getInstance(String url, String instanceId,
TokenManager tokenManager) {
if (url.endsWith("/")) {
// trim off trailing slash
url = url.substring(0, url.length() - 1);
}
return new ServiceAccount(url, instanceId, tokenManager);
}
/**
* Returns an instance of ServiceAccount. This factory method tries below in order.
*
* - Checks environment variables
GP_URL
(service URL - e.g.
* https://gp-rest.ng.bluemix.net/translate/rest), GP_INSTANCE_ID
* (service instance ID - e.g. d3f537cd617f34c86ac6b270f3065e73),
* GP_USER_ID
(user ID - e.g. e92a1282a0e4f97bec93aa9f56fdb838)
* and GP_PASSWORD
(password - e.g. zg5SlD+ftXYRIZDblLgEA/ILkkCNqE1y).
* If all of above are defined, this method calls
* {@link #getInstance(String, String, String, String)} with these environment
* variable values.
*
* - Checks
VCAP_SERVICES
environment variable. If the variable
* is defined and an entry for IBM Globalization Pipeline service is available,
* use the values in the JSON credentials
object. When multiple entries
* for IBM Globalization Pipeline service are found, the first one will be used.
* unless GP_SERVICE_NAME
and/or GP_SERVICE_INSTANCE_NAME
* are not defined.
*
* - If both of above failed, returns null.
*
* @return An instance of ServiceAccount, or null if service configuration is
* not available.
*/
public static ServiceAccount getInstance() {
ServiceAccount account = getInstanceByEnvVars();
if (account == null) {
Map env = System.getenv();
String serviceName = env.get(GP_SERVICE_NAME);
String serviceInstanceName = env.get(GP_SERVICE_INSTANCE_NAME);
account = getInstanceByVcapServices(serviceName, serviceInstanceName);
}
return account;
}
/**
* Returns an instance of ServiceAccount for the specified IBM Globalization
* Pipeline service name and service instance name from VCAP_SERVICES environment
* variable.
*
* If no matching service instance entry is found, this method returns null.
*
* @param serviceName
* The name of IBM Globalization Pipeline service.
* When null, the default service name pattern will be used.
* @param serviceInstanceName
* The name of IBM Globalization Pipeline service instance.
* When null, the first matching entry will be used.
* @return An instance of ServiceAccount for the specified service
* name and service instance name, or null if the matching
* entry was not found.
*/
public static ServiceAccount getInstanceForService(String serviceName, String serviceInstanceName) {
return getInstanceByVcapServices(serviceName, serviceInstanceName);
}
/**
* Returns an instance of ServiceAccount from the environment variables -
* GP_URL, GP_INSTANCE_ID, GP_USER_ID and GP_PASSWORD.
*
* If any of these are not defined, this method returns null.
*
* @return An instance of ServiceAccount initialized by the environment
* variables, or null if any of these are not defined.
*/
private static ServiceAccount getInstanceByEnvVars() {
Map env = System.getenv();
String url = env.get(GP_URL);
String instanceId = env.get(GP_INSTANCE_ID);
String userId = env.get(GP_USER_ID);
String password = env.get(GP_PASSWORD);
String apiKey = env.get(GP_IAM_API_KEY);
String iamBearerToken=env.get(GP_IAM_BEARER_TOKEN);
String iamEndpoint=env.get(GP_IAM_ENDPOINT);
return getInstance(url, instanceId, userId, password, apiKey,
iamBearerToken, iamEndpoint);
}
/**
* @param url
* The service URL of Globlization Pipeline service.
* (e.g. https://gp-rest.ng.bluemix.net/translate/rest)
* @param instanceId
* The instance ID of the service instance.
* (e.g. d3f537cd617f34c86ac6b270f3065e73)
* @param userId
* The user ID for the service instance.
* (e.g. e92a1282a0e4f97bec93aa9f56fdb838)
* @param password
* The password for the service instance.
* (e.g. zg5SlD+ftXYRIZDblLgEA/ILkkCNqE1y)
* @param iamEndpoint
* IAM endpoint.
* @param iamBearerToken
* IAM Bearer token.
* @param apiKey
* IAM API Key.
* @return An instance of ServiceAccount, or null if essential params are not available.
*/
static ServiceAccount getInstance(String url, String instanceId,
String userId, String password, String apiKey,
String iamBearerToken, String iamEndpoint) {
if(url == null || instanceId == null) {
logger.config(
"Not enough environment variables to initialize an instance of ServiceAccount with either Globalization Pipeline Authentication or IAM Authorization. Globalization Pipeline URL and instance id are required.");
return null;
}
if (userId == null || password == null) {
logger.config("Not enough environment variables to initialize an instance of ServiceAccount supporting Globalization Pipeline Authentication.");
}
else {
ServiceAccount account = getInstance(url, instanceId, userId, password);
logger.config("A ServiceAccount is created from environment variables: GP_URL="
+ url + ", GP_INSTANCE_ID=" + instanceId + ", GP_USER_ID=" +
userId + ", GP_PASSWORD=***");
return account;
}
if(iamEndpoint==null||iamEndpoint.isEmpty()) {
logger.config("Not enough environment variables to initialize an instance of ServiceAccount supporting IAM Authorization. IAM endpoint is either not set or blank.");
return null;
}
if (apiKey==null||apiKey.isEmpty()) {
logger.config("Not enough environment variables to initialize an instance of ServiceAccount supporting IAM Authorization using IAM API Key.");
}
else {
ServiceAccount account = getInstance(url, instanceId, TokenManagerFactory.getTokenLifeCycleManager(iamEndpoint, apiKey));
logger.config("A ServiceAccount is created from environment variables: GP_URL="
+ url + ", GP_INSTANCE_ID=" + instanceId + ", GP_IAM_API_KEY=***");
return account;
}
if (iamBearerToken==null||iamBearerToken.isEmpty()) {
logger.config("Not enough environment variables to initialize an instance of ServiceAccount supporting IAM Authorization using IAM bearer token.");
return null;
}
else {
ServiceAccount account = getInstance(url, instanceId, TokenManagerFactory.getTokenManager(iamBearerToken));
logger.config("A ServiceAccount is created from environment variables: GP_URL="
+ url + ", GP_INSTANCE_ID=" +instanceId+ ", GP_IAM_BEARER_TOKEN=***");
return account;
}
}
/**
* Returns an instance of ServiceAccount from the VCAP_SERVICES environment
* variable.
*
* When serviceInstanceName
is null, this method returns
* a ServiceAccount for the first valid IBM Globlization Pipeline service instance.
* If serviceInstanceName
is not null, this method look up a
* matching service entry, and returns a ServiceAccount for the matching entry.
* If serviceInstanceName
is not null and there is no match,
* this method returns null.
*
* @param serviceName
* The name of IBM Globalization Pipeline service. If null,
* the first service with a name matching GP_SERVICE_NAME_PATTERN
* will be used.
* @param serviceInstanceName
* The name of IBM Globalization Pipeline service instance, or null
* designating the first available service instance.
* @return An instance of ServiceAccount for the specified service instance
* name, or null.
*/
private static ServiceAccount getInstanceByVcapServices(String serviceName, String serviceInstanceName) {
Map env = System.getenv();
String vcapServices = env.get("VCAP_SERVICES");
if (vcapServices == null) {
return null;
}
try {
JsonObject obj = new JsonParser().parse(vcapServices).getAsJsonObject();
// When service name is specified,
// this method returns only a matching entry
if (serviceName != null) {
JsonElement elem = obj.get(serviceName);
if (elem != null && elem.isJsonArray()) {
return parseToServiceAccount(elem.getAsJsonArray(), serviceInstanceName);
}
}
// Otherwise, lookup a valid entry with a name matching
// the default pattern GP_SERVICE_NAME_PATTERN.
for (Entry entry : obj.entrySet()) {
String name = entry.getKey();
JsonElement elem = entry.getValue();
if (elem.isJsonArray() && GP_SERVICE_NAME_PATTERN.matcher(name).matches()) {
ServiceAccount account = parseToServiceAccount(elem.getAsJsonArray(), serviceInstanceName);
if (account != null) {
return account;
}
}
}
} catch (JsonParseException e) {
// Fall through - will return null
}
return null;
}
/**
* Returns an instance of ServiceAccount for a JsonArray in the VCAP_SERVICES environment.
*
* This method is called from {@link #getInstanceByVcapServices(String, String)}.
*
* @param jsonArray
* The candidate JSON array which may include valid credentials.
* @param serviceInstanceName
* The name of IBM Globalization Pipeline service instance, or null
* designating the first available service instance.
* @return An instance of ServiceAccount. This method returns null if no matching service
* instance name was found (when serviceInstanceName is null), or no valid
* credential data was found.
*/
private static ServiceAccount parseToServiceAccount(JsonArray jsonArray, String serviceInstanceName) {
ServiceAccount account = null;
for (int i = 0; i < jsonArray.size(); i++) {
JsonObject gpObj = jsonArray.get(i).getAsJsonObject();
if (serviceInstanceName != null) {
// When service instance name is specified,
// this method returns only a matching entry
JsonPrimitive name = gpObj.getAsJsonPrimitive("name");
if (name == null || !serviceInstanceName.equals(name.getAsString())) {
continue;
}
}
JsonObject credentials = gpObj.getAsJsonObject("credentials");
if (credentials == null) {
continue;
}
JsonPrimitive jsonUrl = credentials.getAsJsonPrimitive("url");
JsonPrimitive jsonInstanceId = credentials.getAsJsonPrimitive("instanceId");
JsonPrimitive jsonUserId = credentials.getAsJsonPrimitive("userId");
JsonPrimitive jsonPassword = credentials.getAsJsonPrimitive("password");
JsonPrimitive jsonIamEndpoint = credentials.getAsJsonPrimitive("iam_endpoint");
JsonPrimitive jsonIamApiKey = credentials.getAsJsonPrimitive("apikey");
if (jsonUrl != null && jsonInstanceId != null) {
if (jsonUserId != null && jsonPassword != null) {
account = getInstance(jsonUrl.getAsString(),
jsonInstanceId.getAsString(),
jsonUserId.getAsString(),
jsonPassword.getAsString());
logger.config(
"A ServiceAccount is created from VCAP_SERVICES: url="
+ jsonUrl + ", instanceId=" + jsonInstanceId
+ ", userId=" + jsonUserId
+ ", password=***");
break;
} else if (jsonIamEndpoint != null && jsonIamApiKey != null) {
account = getInstance(jsonUrl.getAsString(),
jsonInstanceId.getAsString(),
TokenManagerFactory.getTokenLifeCycleManager(
jsonIamEndpoint.getAsString(),
jsonIamApiKey.getAsString()));
logger.config(
"A ServiceAccount is created from VCAP_SERVICES: url="
+ jsonUrl + ", instanceId=" + jsonInstanceId
+ ", iam_endpoint=" + jsonIamEndpoint
+ ", apikey=***");
break;
}
}
}
return account;
}
/**
* Is this is an IAM enabled account?
* @return true if account is IAM enabled.
*/
public boolean isIamEnabled() {
return tokenManager!=null;
}
/**
* IAM bearer token for the account.
* @return IAM bearer token for the account
*/
public String getIamToken() throws TokenManagerException {
return tokenManager.getToken();
}
/**
* Returns the URL of IBM Globalization Pipeline service.
*
* @return The URL of IBM Globalization Pipeline service.
*/
public String getUrl() {
return url;
}
/**
* Returns the ID of IBM Globalization Pipeline service instance.
*
* @return The ID of IBM Globalization Pipeline service instance.
*/
public String getInstanceId() {
return instanceId;
}
/**
* Returns the user ID used for the service instance.
* @return The user ID used for the service instance.
*/
public String getUserId() {
return userId;
}
/**
* Returns the password used for the service instance.
* @return The password used for the service instance.
*/
public String getPassword() {
return password;
}
}