Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Modularize AccessToken class #272

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ test.finalizedBy jacocoTestReport
test {
useJUnitPlatform()
reports {
junitXml.enabled = false
html.enabled = true
junitXml.required.set(false)
html.required.set(true)
}
}

Expand Down
70 changes: 4 additions & 66 deletions src/main/java/com/amadeus/client/AccessToken.java
Original file line number Diff line number Diff line change
@@ -1,85 +1,23 @@
package com.amadeus.client;

import com.amadeus.Configuration;
import com.amadeus.Constants;
import com.amadeus.HTTPClient;
import com.amadeus.HttpVerbs;
import com.amadeus.Params;
import com.amadeus.Response;
import com.amadeus.exceptions.ResponseException;
import com.google.gson.JsonObject;

/**
* A memoized Access Token, with the ability to auto-refresh when needed.
* @hide as only used internally
*/
public class AccessToken {
// Renew the token 10 seconds earlier than required,
// just to account for system lag
private static final long TOKEN_BUFFER = 10000L;
// An instance of the API client
private final HTTPClient client;
// The access token value
private String accessToken = null;
// The (UNIX) expiry time of this token
private long expiresAt;
private final TokenManager tokenManager;

/**
* Constructor.
* @hides as only used internally
*/
public AccessToken(HTTPClient client) {
this.client = client;
this.tokenManager = new TokenManager(client);
}

/**
* Creates a Bearer header using the cached Access Token.
* @hides as only used internally
*/
public String getBearerToken() throws ResponseException {
lazyUpdateAccessToken();
return String.format("Bearer %s", accessToken);
}

// Loads the access token if it's still null
// or has expired.
private void lazyUpdateAccessToken() throws ResponseException {
if (needsRefresh()) {
updateAccessToken();
}
}

// Fetches the access token and then parses the resuling values.
private void updateAccessToken() throws ResponseException {
Response response = fetchAccessToken();
storeAccessToken(response.getResult());
}

// Checks if this access token needs a refresh.
private boolean needsRefresh() {
boolean isNull = accessToken == null;
boolean expired = (System.currentTimeMillis() + TOKEN_BUFFER) > expiresAt;
return isNull || expired;
}

// Fetches a new Access Token using the credentials from the client
private Response fetchAccessToken() throws ResponseException {
Configuration config = client.getConfiguration();
return client.unauthenticatedRequest(
HttpVerbs.POST,
Constants.AUTH_URL,
Params.with(Constants.GRANT_TYPE, Constants.CLIENT_CREDENTIALS)
.and(Constants.CLIENT_ID, config.getClientId())
.and(Constants.CLIENT_SECRET, config.getClientSecret()),
null,
null
);
}

// Store the fetched access token and expiry date
private void storeAccessToken(JsonObject result) {
this.accessToken = result.get(Constants.ACCESS_TOKEN).getAsString();
int expiresIn = result.get(Constants.EXPIRES_IN).getAsInt();
this.expiresAt = System.currentTimeMillis() + expiresIn * 1000L;
tokenManager.lazyUpdateAccessToken();
return String.format("Bearer %s", tokenManager.getTokenValue());
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/amadeus/client/AuthUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.amadeus.client;

import com.amadeus.Configuration;
import com.amadeus.Constants;
import com.amadeus.HTTPClient;
import com.amadeus.HttpVerbs;
import com.amadeus.Params;
import com.amadeus.Response;
import com.amadeus.exceptions.ResponseException;

/**
* Utility class for authentication-related operations.
*/
public class AuthUtils {

private AuthUtils() {
// Prevent instantiation
}

public static Params createAuthRequestParams(Configuration config) {
return Params.with(Constants.GRANT_TYPE, Constants.CLIENT_CREDENTIALS)
.and(Constants.CLIENT_ID, config.getClientId())
.and(Constants.CLIENT_SECRET, config.getClientSecret());
}

public static Response executeUnauthenticatedRequest(HTTPClient client, Params params)
throws ResponseException {
return client.unauthenticatedRequest(
HttpVerbs.POST,
Constants.AUTH_URL,
params,
null,
null
);
}
}
62 changes: 62 additions & 0 deletions src/main/java/com/amadeus/client/TokenManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.amadeus.client;

import com.amadeus.Configuration;
import com.amadeus.Constants;
import com.amadeus.HTTPClient;
import com.amadeus.Params;
import com.amadeus.Response;
import com.amadeus.exceptions.ResponseException;
import com.google.gson.JsonObject;
import lombok.Getter;

/**
* Handles token-related functionality, including fetching and refreshing tokens.
*/
public class TokenManager {
private static final long TOKEN_BUFFER = 10000L;
private static final long MILLISECONDS_IN_SECOND = 1000L;

private final HTTPClient client;
@Getter
private String tokenValue = null;
private long expiresAt;

public TokenManager(HTTPClient client) {
this.client = client;
}

public void lazyUpdateAccessToken() throws ResponseException {
if (isTokenExpiredOrNull()) {
updateAccessToken();
}
}

private boolean isTokenExpiredOrNull() {
return isTokenNull() || isTokenExpired();
}

private boolean isTokenNull() {
return tokenValue == null;
}

private boolean isTokenExpired() {
return (System.currentTimeMillis() + TOKEN_BUFFER) > expiresAt;
}

private void updateAccessToken() throws ResponseException {
Configuration config = client.getConfiguration();
Params requestParams = AuthUtils.createAuthRequestParams(config);
Response response = AuthUtils.executeUnauthenticatedRequest(client, requestParams);
storeAccessTokenDetails(response.getResult());
}

private void storeAccessTokenDetails(JsonObject result) {
this.tokenValue = result.get(Constants.ACCESS_TOKEN).getAsString();
int expiresIn = result.get(Constants.EXPIRES_IN).getAsInt();
this.expiresAt = calculateExpiryTime(expiresIn);
}

private long calculateExpiryTime(int expiresIn) {
return System.currentTimeMillis() + expiresIn * MILLISECONDS_IN_SECOND;
}
}