Skip to content

Commit

Permalink
WIP for transitioning to Java HTTP lib
Browse files Browse the repository at this point in the history
  • Loading branch information
nightowlengineer committed Nov 9, 2023
1 parent 0cb8efb commit 64bbcde
Show file tree
Hide file tree
Showing 12 changed files with 360 additions and 450 deletions.
5 changes: 0 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,6 @@
<artifactId>commons-lang3</artifactId>
<version>3.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
Expand Down
52 changes: 12 additions & 40 deletions src/main/java/engineer/nightowl/sonos/api/SonosApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@
import engineer.nightowl.sonos.api.resource.PlaylistResource;
import engineer.nightowl.sonos.api.resource.SettingsResource;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.VersionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.http.HttpClient;
import java.util.Properties;

public class SonosApiClient implements AutoCloseable
public class SonosApiClient
{
// Resources
private final AudioClipResource audioClipResource;
Expand All @@ -48,7 +46,7 @@ public class SonosApiClient implements AutoCloseable

// Can be overridden by implementing applications
private SonosApiConfiguration configuration;
private CloseableHttpClient httpClient;
private HttpClient httpClient;

private final String version;

Expand All @@ -58,7 +56,7 @@ public class SonosApiClient implements AutoCloseable
* @param configuration a {@link engineer.nightowl.sonos.api.SonosApiConfiguration} containing integration
* information such as API keys
*
* @see SonosApiClient#SonosApiClient(SonosApiConfiguration, CloseableHttpClient)
* @see SonosApiClient#SonosApiClient(SonosApiConfiguration, HttpClient)
*/
public SonosApiClient(final SonosApiConfiguration configuration)
{
Expand All @@ -70,9 +68,9 @@ public SonosApiClient(final SonosApiConfiguration configuration)
*
* @param configuration a {@link engineer.nightowl.sonos.api.SonosApiConfiguration} containing integration
* information such as API keys
* @param httpClient a custom {@link CloseableHttpClient} - if null, a default client is initialised
* @param httpClient a custom {@link HttpClient} - if null, a default client is initialised
*/
public SonosApiClient(final SonosApiConfiguration configuration, final CloseableHttpClient httpClient)
public SonosApiClient(final SonosApiConfiguration configuration, final HttpClient httpClient)
{
loadProperties();
version = properties.getProperty("sonosapijava.version");
Expand Down Expand Up @@ -101,44 +99,27 @@ public SonosApiClient(final SonosApiConfiguration configuration, final Closeable

public String getUserAgent()
{
final String ahcUa = VersionInfo.getUserAgent("Apache-HttpClient",
"org.apache.http.client", HttpClientBuilder.class);

return String.format("sonos-api-java/%s (applicationId/%s) (httpClient/(%s))",
version, configuration.getApplicationId(), ahcUa);
return String.format("sonos-api-java/%s (applicationId/%s))",
version, configuration.getApplicationId());
}

/**
* Generate a default HTTP client.
*
* @return a default HTTP client.
*/
private CloseableHttpClient generateHttpClient()
private HttpClient generateHttpClient()
{
logger.debug("Using default HttpClient");
return HttpClientBuilder.create().setUserAgent(getUserAgent()).build();
}

/**
* Close the HTTP client.
*/
public void closeHttpClient()
{
try
{
httpClient.close();
} catch (final IOException ioe)
{
logger.warn("Unable to close HttpClient", ioe);
}
return HttpClient.newHttpClient();
}

/**
* Get the configured HTTP client for this API client instance.
*
* @return the configured HTTP client
*/
public CloseableHttpClient getHttpClient()
public HttpClient getHttpClient()
{
return httpClient;
}
Expand All @@ -148,7 +129,7 @@ public CloseableHttpClient getHttpClient()
*
* @param httpClient custom client to set
*/
public void setHttpClient(final CloseableHttpClient httpClient)
public void setHttpClient(final HttpClient httpClient)
{
this.httpClient = httpClient;
}
Expand Down Expand Up @@ -323,13 +304,4 @@ public SettingsResource settings()
return settingsResource;
}


/**
* Closes the HttpClient
*/
@Override
public void close()
{
closeHttpClient();
}
}
156 changes: 37 additions & 119 deletions src/main/java/engineer/nightowl/sonos/api/SonosApiConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package engineer.nightowl.sonos.api;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import java.util.Base64;
import java.util.Objects;

/**
* Configuration class to be built up and passed into a {@link engineer.nightowl.sonos.api.SonosApiClient}
* Configuration class to be built up and passed into a
* {@link engineer.nightowl.sonos.api.SonosApiClient}
* <p>
* Loads defaults on construction.
*/
Expand All @@ -21,172 +19,92 @@ public class SonosApiConfiguration
private String controlBaseUrl;
private Boolean clientSideValidationEnabled;

/**
* <p>Constructor for SonosApiConfiguration.</p>
*/
public SonosApiConfiguration()
{
public SonosApiConfiguration() {
loadDefaults();
}

/**
* <p>Getter for the field <code>applicationId</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getApplicationId()
{
public String getApplicationId() {
return applicationId;
}

/**
* <p>Setter for the field <code>applicationId</code>.</p>
*
* @param applicationId a {@link java.lang.String} object.
*/
public void setApplicationId(final String applicationId)
{
public void setApplicationId(final String applicationId) {
this.applicationId = applicationId;
}

/**
* <p>Getter for the field <code>apiKey</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getApiKey()
{
public String getApiKey() {
return apiKey;
}

/**
* <p>Setter for the field <code>apiKey</code>.</p>
*
* @param apiKey a {@link java.lang.String} object.
*/
public void setApiKey(final String apiKey)
{
public void setApiKey(final String apiKey) {
this.apiKey = apiKey;
}

public String getApiSecret()
{
public String getApiSecret() {
return apiSecret;
}

/**
* <p>Setter for the field <code>apiSecret</code>.</p>
*
* @param apiSecret a {@link java.lang.String} object.
*/
public void setApiSecret(final String apiSecret)
{
public void setApiSecret(final String apiSecret) {
this.apiSecret = apiSecret;
}

/**
* <p>Getter for the field <code>authBaseUrl</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getAuthBaseUrl()
{
public String getAuthBaseUrl() {
return authBaseUrl;
}

public void setAuthBaseUrl(final String authBaseUrl)
{
public void setAuthBaseUrl(final String authBaseUrl) {
this.authBaseUrl = authBaseUrl;
}

/**
* <p>Getter for the field <code>controlBaseUrl</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getControlBaseUrl()
{
public String getControlBaseUrl() {
return controlBaseUrl;
}

public void setControlBaseUrl(final String controlBaseUrl)
{
public void setControlBaseUrl(final String controlBaseUrl) {
this.controlBaseUrl = controlBaseUrl;
}

public Boolean isClientSideValidationEnabled()
{
public Boolean isClientSideValidationEnabled() {
return clientSideValidationEnabled;
}

public void setClientSideValidationEnabled(Boolean clientSideValidationEnabled)
{
public void setClientSideValidationEnabled(Boolean clientSideValidationEnabled) {
this.clientSideValidationEnabled = clientSideValidationEnabled;
}


public void loadDefaults()
{
public void loadDefaults() {
setAuthBaseUrl("api.sonos.com");
setControlBaseUrl("api.ws.sonos.com/control/api");
setClientSideValidationEnabled(Boolean.TRUE);
}

/**
* <p>getAuthorizationHeader.</p>
*
* @return a {@link org.apache.http.Header} object.
*/
public Header getAuthorizationHeader()
{
public String getAuthorizationHeaderValue() {
final byte[] authBytes = String.join(":", getApiKey(), getApiSecret()).getBytes();
final String authBase64 = Base64.encodeBase64String(authBytes);
final String headerValue = String.join(" ", "Basic", authBase64);
return new BasicHeader("Authorization", headerValue);
final String authBase64 = Base64.getEncoder().encodeToString(authBytes);
return String.join(" ", "Basic", authBase64);
}

@Override
public String toString()
{
return "SonosApiConfiguration{" +
"applicationId='" + applicationId + '\'' +
", apiKey='" + apiKey + '\'' +
", apiSecret='" + apiSecret + '\'' +
", authBaseUrl='" + authBaseUrl + '\'' +
", controlBaseUrl='" + controlBaseUrl + '\'' +
", clientSideValidationEnabled=" + clientSideValidationEnabled +
'}';
public String toString() {
return "SonosApiConfiguration [apiKey=" + apiKey + ", apiSecret=" + apiSecret + ", applicationId="
+ applicationId + ", authBaseUrl=" + authBaseUrl + ", clientSideValidationEnabled="
+ clientSideValidationEnabled + ", controlBaseUrl=" + controlBaseUrl + "]";
}

@Override
public boolean equals(Object o)
{
if (this == o) return true;

if (o == null || getClass() != o.getClass()) return false;

SonosApiConfiguration that = (SonosApiConfiguration) o;

return new EqualsBuilder()
.append(applicationId, that.applicationId)
.append(apiKey, that.apiKey)
.append(apiSecret, that.apiSecret)
.append(authBaseUrl, that.authBaseUrl)
.append(controlBaseUrl, that.controlBaseUrl)
.append(clientSideValidationEnabled, that.clientSideValidationEnabled)
.isEquals();
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof SonosApiConfiguration))
return false;
SonosApiConfiguration other = (SonosApiConfiguration) obj;
return Objects.equals(apiKey, other.apiKey) && Objects.equals(apiSecret, other.apiSecret)
&& Objects.equals(applicationId, other.applicationId) && Objects.equals(authBaseUrl, other.authBaseUrl)
&& Objects.equals(clientSideValidationEnabled, other.clientSideValidationEnabled)
&& Objects.equals(controlBaseUrl, other.controlBaseUrl);
}

@Override
public int hashCode()
{
return new HashCodeBuilder(17, 37)
.append(applicationId)
.append(apiKey)
.append(apiSecret)
.append(authBaseUrl)
.append(controlBaseUrl)
.append(clientSideValidationEnabled)
.toHashCode();
public int hashCode() {
return Objects.hash(apiKey, apiSecret, applicationId, authBaseUrl, clientSideValidationEnabled, controlBaseUrl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
public class SonosSessionError extends SonosApiError
{
private static final long serialVersionUID = 9183301150166556145L;
private String sessionId;
private SonosSessionErrorCode errorCode;
}
Loading

0 comments on commit 64bbcde

Please sign in to comment.