package com.intrbiz.bergamot;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.fluent.Executor;
import org.apache.http.client.fluent.Response;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import com.intrbiz.Util;
import com.intrbiz.bergamot.call.ApplyConfigChangeCall;
import com.intrbiz.bergamot.call.BuildSiteConfigCall;
import com.intrbiz.bergamot.call.GoodbyeCruelWorldCall;
import com.intrbiz.bergamot.call.HelloWorldCall;
import com.intrbiz.bergamot.call.HelloYouCall;
import com.intrbiz.bergamot.call.LookingForSomethingCall;
import com.intrbiz.bergamot.call.SignAgentKey;
import com.intrbiz.bergamot.credentials.BasicCredentials;
import com.intrbiz.bergamot.credentials.ClientCredentials;
import com.intrbiz.bergamot.credentials.TokenCredentials;
import com.intrbiz.bergamot.crypto.util.BergamotTrustManager;
import com.intrbiz.bergamot.io.BergamotTranscoder;
import com.intrbiz.bergamot.model.message.AuthTokenMO;
public abstract class BaseBergamotClient
{
protected final BergamotTranscoder transcoder = new BergamotTranscoder();
// the API base url
protected final String baseURL;
// the credentials to authenticate with
protected ClientCredentials credentials;
// the current auth token
protected AuthTokenMO authToken;
// customised HTTPClient
protected Registry<ConnectionSocketFactory> schemeRegistry;
protected PoolingHttpClientConnectionManager connectionManager;
protected HttpClient client;
protected Executor executor;
public BaseBergamotClient(String baseURL)
{
super();
// remove trailing /
if (baseURL.endsWith("/"))
{
baseURL = baseURL.substring(0, baseURL.length() - 1);
}
this.baseURL = baseURL;
// setup our executor
try
{
// custom TLS handling
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] { new BergamotTrustManager(Boolean.getBoolean("bergamot.api.allow-invalid-certs")) }, new SecureRandom());
// scheme registry
this.schemeRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", new SSLConnectionSocketFactory(ctx))
.build();
// create out connection manager
this.connectionManager = new PoolingHttpClientConnectionManager(this.schemeRegistry);
this.connectionManager.setDefaultMaxPerRoute(5);
this.connectionManager.setMaxTotal(10);
// create our client
this.client = HttpClientBuilder.create().setConnectionManager(this.connectionManager).build();
// create our executor
this.executor = Executor.newInstance(this.client);
}
catch (KeyManagementException | NoSuchAlgorithmException e)
{
throw new RuntimeException("Failed to setup HTTP client", e);
}
}
public BaseBergamotClient(String baseURL, ClientCredentials credentials)
{
this(baseURL);
this.credentials = credentials;
}
public BaseBergamotClient(String baseURL, String token)
{
this(baseURL);
this.credentials = new TokenCredentials(token);
}
public BaseBergamotClient(String baseURL, String username, String password)
{
this(baseURL);
this.credentials = new BasicCredentials(username, password);
}
public BergamotTranscoder transcoder()
{
return this.transcoder;
}
// HTTP Client Executor
public Executor executor()
{
return this.executor;
}
// the base url
public String getBaseURL()
{
return this.baseURL;
}
// current auth details
public ClientCredentials getCredentials()
{
return this.credentials;
}
public void setAuthToken(AuthTokenMO authToken)
{
this.authToken = authToken;
}
public AuthTokenMO getAuthToken()
{
if (this.authTokenExpired())
{
this.authToken = this.credentials.auth(this);
}
return authToken;
}
public boolean authTokenExpired()
{
return this.authToken == null || (this.authToken.getExpiresAt() > 0 && this.authToken.getExpiresAt() < System.currentTimeMillis());
}
// create a full URL from the following path element
public String url(String... urlElements)
{
StringBuilder sb = new StringBuilder(this.baseURL);
for (String urlElement : urlElements)
{
sb.append(urlElement);
}
return sb.toString();
}
public String appendQuery(String url, NameValuePair... parameters)
{
StringBuilder sb = new StringBuilder(url);
sb.append("?");
boolean ns = false;
for (NameValuePair parameter : parameters)
{
if (ns) sb.append("&");
sb.append(Util.urlEncode(parameter.getName(), Util.UTF8)).append("=").append(Util.urlEncode(parameter.getValue(), Util.UTF8));
ns = true;
}
return sb.toString();
}
public String appendQuery(String url, Iterable<NameValuePair> parameters)
{
StringBuilder sb = new StringBuilder(url);
sb.append("?");
boolean ns = false;
for (NameValuePair parameter : parameters)
{
if (ns) sb.append("&");
sb.append(Util.urlEncode(parameter.getName(), Util.UTF8)).append("=").append(Util.urlEncode(parameter.getValue(), Util.UTF8));
ns = true;
}
return sb.toString();
}
// auth calls
public static class GetAuthTokenCall extends BergamotAPICall<AuthTokenMO>
{
private String username;
private String password;
public GetAuthTokenCall(BaseBergamotClient client)
{
super(client);
}
public GetAuthTokenCall username(String username)
{
this.username = username;
return this;
}
public GetAuthTokenCall password(String password)
{
this.password = password;
return this;
}
public AuthTokenMO execute()
{
try
{
Response response = execute(
post(url("/api/auth-token"))
.addHeader(authHeader())
.bodyForm(
param("username", this.username),
param("password", this.password)
)
);
return transcoder().decodeFromString(response.returnContent().asString(), AuthTokenMO.class);
}
catch (IOException e)
{
throw new BergamotAPIException("Error calling Bergamot Monitoring API", e);
}
}
}
public GetAuthTokenCall callGetAuthToken()
{
return new GetAuthTokenCall(this);
}
// test calls
public HelloWorldCall callHelloWorld()
{
return new HelloWorldCall(this);
}
public HelloYouCall callHelloYou()
{
return new HelloYouCall(this);
}
public GoodbyeCruelWorldCall callGoodbyeCruelWorld()
{
return new GoodbyeCruelWorldCall(this);
}
public LookingForSomethingCall callLookingForSomething()
{
return new LookingForSomethingCall(this);
}
// config
public BuildSiteConfigCall callBuildSiteConfig()
{
return new BuildSiteConfigCall(this);
}
public ApplyConfigChangeCall callApplyConfigChange()
{
return new ApplyConfigChangeCall(this);
}
// agent
public SignAgentKey callSignAgentKey()
{
return new SignAgentKey(this);
}
}