Skip to content
This repository has been archived by the owner on May 31, 2023. It is now read-only.

Minor updates. #25

Merged
merged 2 commits into from Nov 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 31 additions & 36 deletions java/src/main/java/io/outreach/Outreach.java
Expand Up @@ -10,6 +10,7 @@
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Properties;

Expand Down Expand Up @@ -50,6 +51,8 @@ public class Outreach {
* authorization code has been consumed.
*/
private String refreshBearer = null;

private long accessExpires = 0;

private final KeyStore trustStore;
private String apiEndpoint = "";
Expand Down Expand Up @@ -93,13 +96,10 @@ public JSONObject modifyProspect(final int prospectId, final String prospectAttr
// code and subsequent requests will use the refresh token from the initial exchange.
this.fetchAccessToken();

final HttpsURLConnection connection = connectTo(this.apiEndpoint + "/prospects/" + prospectId);
final HttpsURLConnection connection = authorizedConnection("POST", this.apiEndpoint + "/prospects/" + prospectId);

connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("X-HTTP-Method-Override", "PATCH"); // Patch isn't supported in Java's HTTPConnection
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
connection.setRequestProperty("Content-Type", "application/json");

try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
writer.write(prospectAttributes);
Expand Down Expand Up @@ -133,12 +133,9 @@ public JSONObject addProspect(final String prospect) {
// code and subsequent requests will use the refresh token from the initial exchange.
this.fetchAccessToken();

final HttpsURLConnection connection = connectTo(this.apiEndpoint + "/prospects");
final HttpsURLConnection connection = authorizedConnection("POST", this.apiEndpoint + "/prospects");

connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
connection.setRequestProperty("Content-Type", "application/json");

try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
writer.write(prospect);
Expand Down Expand Up @@ -167,10 +164,7 @@ public JSONObject getProspect(final int prospectId) {
// code and subsequent requests will use the refresh token from the initial exchange.
this.fetchAccessToken();

final HttpsURLConnection connection = connectTo(this.apiEndpoint + "/prospects/" + prospectId);

connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
final HttpsURLConnection connection = authorizedConnection("GET", this.apiEndpoint + "/prospects/" + prospectId);

final JSONObject response;
try (BufferedReader readStream = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
Expand Down Expand Up @@ -220,9 +214,7 @@ public JSONObject getProspects(final String firstName, final String lastName, fi

query = query.substring(0, query.length() - 1); // last character will always be a superfluous ? or &

final HttpsURLConnection connection = connectTo(this.apiEndpoint + query);
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
final HttpsURLConnection connection = authorizedConnection("GET", this.apiEndpoint + query);

final JSONObject response;
try (BufferedReader readStream = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
Expand All @@ -247,10 +239,7 @@ public JSONObject getSequences(final int page) {
// code and subsequent requests will use the refresh token from the initial exchange.
this.fetchAccessToken();

final HttpsURLConnection connection = connectTo(this.apiEndpoint + "/sequences?page[number]=" + page);

connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
final HttpsURLConnection connection = authorizedConnection("GET", this.apiEndpoint + "/sequences?page[number]=" + page);

final JSONObject response;
try (BufferedReader readStream = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
Expand All @@ -277,13 +266,10 @@ public JSONObject addProspectsToSequence(final int sequenceId, final String payl
// code and subsequent requests will use the refresh token from the initial exchange.
this.fetchAccessToken();

final HttpsURLConnection connection = connectTo(this.apiEndpoint + "/sequences/" + sequenceId);
final HttpsURLConnection connection = authorizedConnection("POST", this.apiEndpoint + "/sequences/" + sequenceId);

connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("X-HTTP-Method-Override", "PATCH"); // Patch isn't supported in Java's HTTPConnection
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
connection.setRequestProperty("Content-Type", "application/json");

try (OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream())) {
writer.write(payload);
Expand Down Expand Up @@ -311,10 +297,7 @@ public JSONObject getInfo() {
// code and subsequent requests will use the refresh token from the initial exchange.
this.fetchAccessToken();

final HttpsURLConnection connection = connectTo(this.apiEndpoint + "/info");

connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
final HttpsURLConnection connection = authorizedConnection("GET", this.apiEndpoint + "/info");

final JSONObject response;
try (BufferedReader readStream = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
Expand All @@ -327,23 +310,30 @@ public JSONObject getInfo() {
}
}

private HttpsURLConnection connectTo(String urlString) throws MalformedURLException,
IOException,
KeyManagementException,
NoSuchAlgorithmException {
return connectTo(new URL(urlString));
private HttpsURLConnection connectTo(String verb, String urlString) throws IOException, NoSuchAlgorithmException, KeyManagementException {
return connectTo(verb, new URL(urlString));
}

private HttpsURLConnection connectTo(URL url) throws IOException, NoSuchAlgorithmException, KeyManagementException {
private HttpsURLConnection connectTo(String verb, URL url) throws IOException, NoSuchAlgorithmException, KeyManagementException {
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

if (trustStore != null) {
connection.setSSLSocketFactory(TrustedSSLSocketFactory.get(trustStore));
connection.setHostnameVerifier(new TrustedHostnameVerifier(trustStore));
}

connection.setRequestMethod(verb);

return connection;
}

private HttpsURLConnection authorizedConnection(String verb, String url) throws IOException, NoSuchAlgorithmException, KeyManagementException {
final HttpsURLConnection connection = connectTo(verb, url);
connection.setRequestProperty("Authorization", new String("Bearer " + this.requestBearer));
connection.setRequestProperty("Content-Type", "application/json");

return connection;
}

/**
* Creates a new bearer token associated with this instance, this must be
Expand All @@ -359,10 +349,14 @@ private HttpsURLConnection connectTo(URL url) throws IOException, NoSuchAlgorith
*/
private void fetchAccessToken() {
try {
final HttpsURLConnection connection = connectTo(this.authEndpoint + "/oauth/token");
// If access token hasn't expired (with some leeway for clock skew) use existing access token
if (this.accessExpires - 1000 > System.currentTimeMillis()) {
return;
}

final HttpsURLConnection connection = connectTo("POST", this.authEndpoint + "/oauth/token");

connection.setDoOutput(true);
connection.setRequestMethod("POST");

// Use a refresh token if one was previously provided.
final String token;
Expand All @@ -389,10 +383,11 @@ private void fetchAccessToken() {

this.requestBearer = response.get("access_token").toString();
this.refreshBearer = response.get("refresh_token").toString();
// Expires_in is defined in seconds
this.accessExpires = System.currentTimeMillis() + (Long.parseLong(response.get("expires_in").toString()) * 1000);
} catch (Throwable throwable) {
throw new OutreachSecurityException(throwable);
}

}

public static class ApplicationCredentials {
Expand Down
1 change: 0 additions & 1 deletion java/src/test/java/io/outreach/OutreachProspectTest.java
Expand Up @@ -239,7 +239,6 @@ public void getProspectsByEmail() {
}

JSONObject response = outreach.getProspects(null, null, null, uniqueEmail, 1);

assertNotNull(response);
JSONArray data = (JSONArray) response.get("data");
assertFalse(data.isEmpty()); // NOTE: There's sometimes a consistency race between creation and fetch where unique email doesn't show up.
Expand Down