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

4.0.x #86

Merged
merged 6 commits into from
May 31, 2020
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ dependencies {
implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion

compileOnly "org.projectlombok:lombok:$lombokVersion"
testImplementation "org.projectlombok:lombok:$lombokVersion"
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
testAnnotationProcessor "org.projectlombok:lombok:$lombokVersion"

swaggerCodegen 'io.swagger.codegen.v3:swagger-codegen-cli:3.0.5' // or Swagger Codegen V3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ApiClientFactorySpec extends Specification {
def token = "MTA1YzRhYWRiNzcyYTI0NzliNmMxZTM0MTkwNGM4NGYzYjY0YjBmZjBkYTUxZGVhNDg1NmYyODc1NDM3NDQxOA.aHR0cHM6Ly9zdnI0LnN1cGxhLm9yZw=="

when:
def client = ApiClientFactory.INSTANCE.newApiClient(token, Mock(ApiUsageStatisticsSetter.class))
def client = ApiClientFactory.INSTANCE.newApiClient(token)

then:
client.getHttpClient()
Expand All @@ -45,29 +45,14 @@ class ApiClientFactorySpec extends Specification {
.anyMatch { it == ApiUsageStatisticsInterceptor.class }
}

def "should not add ApiUsageStatisticsInterceptor to interceptors"() {
given:
def token = "MTA1YzRhYWRiNzcyYTI0NzliNmMxZTM0MTkwNGM4NGYzYjY0YjBmZjBkYTUxZGVhNDg1NmYyODc1NDM3NDQxOA.aHR0cHM6Ly9zdnI0LnN1cGxhLm9yZw=="

when:
def client = ApiClientFactory.INSTANCE.newApiClient(token, (ApiUsageStatisticsSetter) null)

then:
!client.getHttpClient()
.interceptors()
.stream()
.map { it.getClass() }
.anyMatch { it == ApiUsageStatisticsInterceptor.class }
}

@Unroll
def "should not verify SSL if property is set to `#property`"(property) {
given:
def token = "MTA1YzRhYWRiNzcyYTI0NzliNmMxZTM0MTkwNGM4NGYzYjY0YjBmZjBkYTUxZGVhNDg1NmYyODc1NDM3NDQxOA.aHR0cHM6Ly9zdnI0LnN1cGxhLm9yZw=="
System.setProperty("jSuplaApi.noVerifyingSsl", property)

when:
def client = ApiClientFactory.INSTANCE.newApiClient(token, (ApiUsageStatisticsSetter) null)
def client = ApiClientFactory.INSTANCE.newApiClient(token)

then:
!client.verifyingSsl
Expand All @@ -83,7 +68,7 @@ class ApiClientFactorySpec extends Specification {
System.setProperty("jSuplaApi.noVerifyingSsl", property)

when:
def client = ApiClientFactory.INSTANCE.newApiClient(token, (ApiUsageStatisticsSetter) null)
def client = ApiClientFactory.INSTANCE.newApiClient(token)

then:
client.verifyingSsl
Expand All @@ -99,7 +84,7 @@ class ApiClientFactorySpec extends Specification {
System.clearProperty("jSuplaApi.noVerifyingSsl")

when:
def client = ApiClientFactory.INSTANCE.newApiClient(token, (ApiUsageStatisticsSetter) null)
def client = ApiClientFactory.INSTANCE.newApiClient(token)

then:
client.verifyingSsl
Expand Down
4 changes: 0 additions & 4 deletions src/main/java/pl/grzeslowski/jsupla/api/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ static Api getInstance(String token) {
return new ApiImpl(token);
}

static Api getInstance(String token, String url) {
return new ApiImpl(token, url);
}

DeviceApi getDeviceApi();

ChannelApi getChannelApi();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,19 @@ public static String getApiVersion() {
/**
* Creates new {@link ApiClient} with given OAuth token and server URL.
*
* @param oAuthToken to authorize
* @param url server base URL
* @param apiUsageStatisticsSetter object to st {@link pl.grzeslowski.jsupla.api.Api.ApiUsageStatistics}
* @param oAuthToken to authorize
* @param url server base URL
* @return new {@link ApiClient} with configured authorization and base path
*/
ApiClient newApiClient(String oAuthToken, String url, ApiUsageStatisticsSetter apiUsageStatisticsSetter) {
private ApiClient newApiClient(String oAuthToken, String url) {
ApiClient client = new ApiClient();
client.setUserAgent("magx2/jSuplaApi");
OAuth password = (OAuth) client.getAuthentication("BearerAuth");
password.setAccessToken(oAuthToken);
client.setBasePath(url + "/api/v" + API_VERSION);
final List<Interceptor> interceptors = client.getHttpClient().interceptors();
interceptors.add(new OneLineHttpLoggingInterceptor(ApiImpl.getLog()::trace, BODY));
if (apiUsageStatisticsSetter != null) {
interceptors.add(new ApiUsageStatisticsInterceptor(apiUsageStatisticsSetter));
}
interceptors.add(new ApiUsageStatisticsInterceptor(ApiUsageStatisticsCollector.INSTANCE.newTokenBound(oAuthToken)));
if (Boolean.getBoolean("jSuplaApi.noVerifyingSsl")) {
client.setVerifyingSsl(false);
}
Expand All @@ -48,11 +45,10 @@ ApiClient newApiClient(String oAuthToken, String url, ApiUsageStatisticsSetter a
/**
* Creates new {@link ApiClient} with given OAuth token.
*
* @param oAuthToken to authorize
* @param apiUsageStatisticsSetter object to st {@link pl.grzeslowski.jsupla.api.Api.ApiUsageStatistics}
* @param oAuthToken to authorize
* @return new {@link ApiClient} with configured authorization and base path
*/
ApiClient newApiClient(String oAuthToken, ApiUsageStatisticsSetter apiUsageStatisticsSetter) {
ApiClient newApiClient(String oAuthToken) {
String[] split = oAuthToken.split("\\.");
if (split.length < 2) {
throw new IllegalArgumentException("OAuth token does not contain '.' (dot)! Token: " + oAuthToken);
Expand All @@ -61,31 +57,6 @@ ApiClient newApiClient(String oAuthToken, ApiUsageStatisticsSetter apiUsageStati
}
String urlBase64 = split[1];
String url = new String(Base64.getDecoder().decode(urlBase64));
return newApiClient(oAuthToken, url, apiUsageStatisticsSetter);
}

/**
* Creates new {@link ApiClient} with given OAuth token and server URL.
*
* @param oAuthToken to authorize
* @param url server base URL
* @return new {@link ApiClient} with configured authorization and base path
* @deprecated use {@link ApiClientFactory#newApiClient(String, String, ApiUsageStatisticsSetter)}
*/
@Deprecated
ApiClient newApiClient(String oAuthToken, String url) {
return newApiClient(oAuthToken, url, null);
}

/**
* Creates new {@link ApiClient} with given OAuth token.
*
* @param oAuthToken to authorize
* @return new {@link ApiClient} with configured authorization and base path
* @deprecated use {@link ApiClientFactory#newApiClient(String, ApiUsageStatisticsSetter)}
*/
@Deprecated
ApiClient newApiClient(String oAuthToken) {
return newApiClient(oAuthToken, (ApiUsageStatisticsSetter) null);
return newApiClient(oAuthToken, url);
}
}
42 changes: 13 additions & 29 deletions src/main/java/pl/grzeslowski/jsupla/api/internal/ApiImpl.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package pl.grzeslowski.jsupla.api.internal;

import io.swagger.client.ApiClient;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import pl.grzeslowski.jsupla.api.Api;
Expand All @@ -11,51 +10,49 @@
import pl.grzeslowski.jsupla.api.LocationApi;
import pl.grzeslowski.jsupla.api.ServerInfoApi;

import java.time.ZonedDateTime;
import java.util.Optional;

import static pl.grzeslowski.jsupla.api.internal.ApiClientFactory.INSTANCE;

@Slf4j
public final class ApiImpl implements Api, ApiUsageStatisticsSetter {
private final ApiClient apiClient;
private ApiUsageStatistics apiUsageStatistics;

public ApiImpl(String token, String url) {
this.apiClient = INSTANCE.newApiClient(token, url, this);
}
public final class ApiImpl implements Api {
private final String token;

public ApiImpl(String token) {
this.apiClient = INSTANCE.newApiClient(token, this);
this.token = token;
}

static Logger getLog() {
return log;
}

private ApiClient newApiClient() {
return INSTANCE.newApiClient(token);
}

@Override
public DeviceApi getDeviceApi() {
return new DeviceApiImpl(apiClient);
return new DeviceApiImpl(newApiClient());
}

@Override
public ChannelApi getChannelApi() {
return new ChannelApiImpl(apiClient);
return new ChannelApiImpl(newApiClient());
}

@Override
public ChannelGroupApi getChannelGroupApi() {
return new ChannelApiImpl(apiClient);
return new ChannelApiImpl(newApiClient());
}

@Override
public LocationApi getLocationApi() {
return new LocationApiImpl(apiClient);
return new LocationApiImpl(newApiClient());
}

@Override
public ServerInfoApi getServerInfoApi() {
return new ServerInfoApiImpl(apiClient);
return new ServerInfoApiImpl(newApiClient());
}

@Override
Expand All @@ -65,19 +62,6 @@ public String getApiVersion() {

@Override
public Optional<ApiUsageStatistics> getApiUsageStatistics() {
return Optional.ofNullable(apiUsageStatistics);
}

@Override
public void setApiUsageStatistics(final ApiUsageStatistics apiUsageStatistics) {
this.apiUsageStatistics = apiUsageStatistics;
}

@Value
static class ApiUsageStatisticsImpl implements ApiUsageStatistics {
ZonedDateTime lastUpdateDate;
int limit;
int remainingLimit;
ZonedDateTime resetDate;
return ApiUsageStatisticsCollector.INSTANCE.getStatistics(token);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package pl.grzeslowski.jsupla.api.internal;

import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import pl.grzeslowski.jsupla.api.Api;

import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static lombok.AccessLevel.PRIVATE;

@NoArgsConstructor(access = PRIVATE)
final class ApiUsageStatisticsCollector {
static final ApiUsageStatisticsCollector INSTANCE = new ApiUsageStatisticsCollector();
private final ConcurrentMap<String, Api.ApiUsageStatistics> cache = new ConcurrentHashMap<>();

TokenBound newTokenBound(@NonNull String token) {
return new TokenBound(token);
}

void putStatistics(@NonNull String token, @NonNull Api.ApiUsageStatistics apiUsageStatistics) {
cache.put(token, apiUsageStatistics);
}

Optional<Api.ApiUsageStatistics> getStatistics(@NonNull String token) {
return Optional.ofNullable(cache.getOrDefault(token, null));
}

@ToString
@RequiredArgsConstructor
final class TokenBound implements ApiUsageStatisticsSetter {
@NonNull private final String token;

@Override
public void setApiUsageStatistics(final Api.ApiUsageStatistics apiUsageStatistics) {
putStatistics(token, apiUsageStatistics);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.Response;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import pl.grzeslowski.jsupla.api.Api;
Expand All @@ -20,6 +22,7 @@

import static java.util.Optional.empty;
import static java.util.Optional.of;
import static lombok.AccessLevel.PRIVATE;

@Slf4j
@RequiredArgsConstructor
Expand Down Expand Up @@ -49,7 +52,7 @@ private Optional<Api.ApiUsageStatistics> buildApiUsageStatistics(final Headers h
final Optional<ZonedDateTime> resetDate = parseResetDate(headers, url);

if (limit.isPresent() && remainingLimit.isPresent() && resetDate.isPresent()) {
return of(new ApiImpl.ApiUsageStatisticsImpl(
return of(new ApiUsageStatisticsImpl(
ZonedDateTime.now(ZoneId.of("UTC")),
limit.get(),
remainingLimit.get(),
Expand Down Expand Up @@ -91,4 +94,13 @@ private Optional<Integer> parseIntFromHeader(final Headers headers, final String
return Optional.empty();
}
}

@Value
@AllArgsConstructor(access = PRIVATE)
static class ApiUsageStatisticsImpl implements Api.ApiUsageStatistics {
ZonedDateTime lastUpdateDate;
int limit;
int remainingLimit;
ZonedDateTime resetDate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;
import lombok.val;

import java.io.IOException;

Expand Down Expand Up @@ -30,7 +31,20 @@ private static final class StringBuilderLogger implements HttpLoggingInterceptor

@Override
public void log(final String message) {
stringBuilder.append("\t").append(message).append("\n");
final String parsedMessage;
if (message.startsWith("Authorization")) {
val noAuth = message.substring(15);
val space = noAuth.indexOf(" ");
if (space > -1) {
val type = noAuth.substring(0, space);
parsedMessage = "Authorization: " + type + " <SECRET>";
} else {
parsedMessage = "Authorization: <SECRET>";
}
} else {
parsedMessage = message;
}
stringBuilder.append("\t").append(parsedMessage).append("\n");
}

String wholeMessage() {
Expand Down
Loading