Skip to content

Commit

Permalink
Preparing update of pom files.
Browse files Browse the repository at this point in the history
Signed-off-by: clinique <gael@lhopital.org>
  • Loading branch information
clinique committed Feb 23, 2022
1 parent 667445a commit 11adb0f
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 104 deletions.
7 changes: 6 additions & 1 deletion bundles/org.openhab.binding.freeboxos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ Note that the discovered thing will be setup to use only HTTP API (and not HTTPS

## Binding configuration

The binding itself is not configurable.
FreeboxOs binding has the following configuration parameters:

| Name | Description | Mandatory |
|-----------------|----------------------------------------------------|-----------|
| timeout | The timeout for reading from the device in seconds | yes |


## Thing Configuration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.binding.freeboxos.internal;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -33,6 +35,7 @@
public class FreeboxOsBindingConstants {

public static final String BINDING_ID = "freeboxos";
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

// List of all Bridge Type UIDs
public static final ThingTypeUID BRIDGE_TYPE_API = new ThingTypeUID(BINDING_ID, "api");
Expand All @@ -48,6 +51,9 @@ public class FreeboxOsBindingConstants {
public static final ThingTypeUID THING_TYPE_VM = new ThingTypeUID(BINDING_ID, "vm");
public static final ThingTypeUID THING_TYPE_REPEATER = new ThingTypeUID(BINDING_ID, "repeater");

// Configuration elements
public static final String TIMEOUT = "timeout";

// All supported Thing types
public static final Set<ThingTypeUID> BRIDGE_TYPE_UID = Set.of(BRIDGE_TYPE_API);
public static final Set<ThingTypeUID> THINGS_TYPES_UIDS = Set.of(THING_TYPE_LANDLINE, THING_TYPE_HOST,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
*/
package org.openhab.binding.freeboxos.internal.api;

import java.lang.reflect.Type;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;

import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
Expand All @@ -27,78 +25,81 @@
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.openhab.core.i18n.TimeZoneProvider;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpStatus.Code;
import org.openhab.binding.freeboxos.internal.api.Response.ErrorCode;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSyntaxException;

/**
* The {@link ApiHandler} is responsible for sending requests toward
* a given url and transform the answer in appropriate dto.
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
@Component(service = ApiHandler.class)
@Component(service = ApiHandler.class, configurationPid = "binding.freeboxos")
public class ApiHandler {
private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(8);
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private static final String AUTH_HEADER = "X-Fbx-App-Auth";
private static final String CONTENT_TYPE = "application/json; charset=" + DEFAULT_CHARSET.name();

private final Logger logger = LoggerFactory.getLogger(ApiHandler.class);
private final HttpClient httpClient;
private final Gson gson;
private final FBDeserializer deserializer;
private long defaultTimeoutInMs = TimeUnit.SECONDS.toMillis(8);

@Activate
public ApiHandler(final @Reference HttpClientFactory httpClientFactory,
final @Reference TimeZoneProvider timeZoneProvider) {
public ApiHandler(@Reference HttpClientFactory httpClientFactory, @Reference FBDeserializer deserializer,
Map<String, Object> config) {
this.httpClient = httpClientFactory.getCommonHttpClient();
this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(ZonedDateTime.class,
(JsonDeserializer<ZonedDateTime>) (json, type, jsonDeserializationContext) -> {
long timestamp = json.getAsJsonPrimitive().getAsLong();
Instant i = Instant.ofEpochSecond(timestamp);
return ZonedDateTime.ofInstant(i, timeZoneProvider.getTimeZone());
})
.create();
this.deserializer = deserializer;
configChanged(config);
}

@Modified
public void configChanged(Map<String, Object> config) {
String timeout = (String) config.get(TIMEOUT);
if (timeout != null) {
defaultTimeoutInMs = TimeUnit.SECONDS.toMillis(Long.parseLong(timeout));
logger.debug("Timeout set to {} seconds", timeout);
}
}

public synchronized <T> T executeUri(URI uri, HttpMethod method, Type classOfT, @Nullable String sessionToken,
public synchronized <T> T executeUri(URI uri, HttpMethod method, Class<T> clazz, @Nullable String sessionToken,
@Nullable Object payload) throws FreeboxException {
logger.debug("executeUrl {} - {} ", method, uri);

Request request = httpClient.newRequest(uri).method(method).header(HttpHeader.CONTENT_TYPE, CONTENT_TYPE);
Request request = httpClient.newRequest(uri).method(method).timeout(defaultTimeoutInMs, TimeUnit.MILLISECONDS)
.header(HttpHeader.CONTENT_TYPE, CONTENT_TYPE);

if (sessionToken != null) {
request.header(AUTH_HEADER, sessionToken);
}

if (payload != null) {
request.content(new StringContentProvider(gson.toJson(payload), DEFAULT_CHARSET), null);
request.content(deserializer.serialize(payload), null);
}

try {
ContentResponse serviceResponse = request.timeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS).send();
String response = new String(serviceResponse.getContent(), DEFAULT_CHARSET);

logger.trace("executeUrl {} - {} returned {}", method, uri, response);

return gson.fromJson(response, classOfT);
} catch (InterruptedException | TimeoutException | ExecutionException | JsonSyntaxException e) {
throw new FreeboxException(e, "Exception while calling " + request.getURI());
ContentResponse response = request.send();
Code statusCode = HttpStatus.getCode(response.getStatus());
String content = new String(response.getContent(), DEFAULT_CHARSET);
logger.trace("executeUrl {} - {} returned {}", method, uri, content);
if (statusCode == Code.OK) {
return deserializer.deserialize(clazz, content);
} else if (statusCode == Code.FORBIDDEN) {
logger.debug("Fobidden, serviceReponse was {}, ", content);
throw new FreeboxException(ErrorCode.AUTHORIZATION_REQUIRED);
}
throw new FreeboxException("Unexpected status code : %d", statusCode);
} catch (InterruptedException | TimeoutException | ExecutionException e) {
throw new FreeboxException(e, "Exception while calling %s", request.getURI());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
\* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.freeboxos.internal.api;

import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.DEFAULT_CHARSET;

import java.time.Instant;
import java.time.ZonedDateTime;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.openhab.core.i18n.TimeZoneProvider;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonSyntaxException;

/**
* The {@link FBDeserializer} is responsible to instantiate suitable Gson (de)serializer
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
@Component(service = FBDeserializer.class)
public class FBDeserializer {
private final Gson gson;

@Activate
public FBDeserializer(@Reference TimeZoneProvider timeZoneProvider) {
gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(ZonedDateTime.class,
(JsonDeserializer<ZonedDateTime>) (json, type, jsonDeserializationContext) -> {
long timestamp = json.getAsJsonPrimitive().getAsLong();
Instant i = Instant.ofEpochSecond(timestamp);
return ZonedDateTime.ofInstant(i, timeZoneProvider.getTimeZone());
})
.create();
}

public <T> T deserialize(Class<T> clazz, String json) throws FreeboxException {
try {
T result = gson.fromJson(json, clazz);
if (result != null) {
return result;
}
throw new FreeboxException("Deserialization of '%s' resulted in null value", json);
} catch (JsonSyntaxException e) {
throw new FreeboxException(e, "Unexpected error deserializing '%s'", json);
}
}

public ContentProvider serialize(Object payload) {
return new StringContentProvider(gson.toJson(payload), DEFAULT_CHARSET);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.freeboxos.internal.api.Response.ErrorCode;

/**
* Exception for errors when using the Freebox API
Expand All @@ -23,23 +24,30 @@
@NonNullByDefault
public class FreeboxException extends Exception {
private static final long serialVersionUID = 9197365222439228186L;

private @Nullable Response<?> response;
private @Nullable ErrorCode errorCode;

public FreeboxException(String msg) {
this(msg, null, null);
super(msg);
}

public FreeboxException(String format, Object... args) {
super(String.format(format, args));
}

public FreeboxException(Exception cause, String format, Object... args) {
super(String.format(format, args), cause);
}

public FreeboxException(Throwable cause, @Nullable String msg) {
this(msg, cause, null);
public FreeboxException(ErrorCode errorCode, String message, @Nullable Exception cause) {
super(message, cause);
this.errorCode = errorCode;
}

public FreeboxException(@Nullable String msg, @Nullable Throwable cause, @Nullable Response<?> response) {
super(msg, cause);
this.response = response;
public FreeboxException(ErrorCode errorCode) {
this(errorCode, errorCode.toString(), null);
}

public @Nullable Response<?> getResponse() {
return response;
public @Nullable ErrorCode getErrorCode() {
return errorCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.osgi.service.component.annotations.Component;

/**
* Provides a TrustManager for the Freebox SSL certificate
* Provides a CertificateManager for the Freebox SSL certificate
*
* @author Gaël L'hopital - Initial Contribution
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,4 @@ public ErrorCode getErrorCode() {
public String getMsg() {
return msg;
}

public static Response<?> of(ErrorCode code) {
Response<?> response = new Response<Object>();
response.success = false;
response.errorCode = code;
return response;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeboxos.internal.api.FreeboxException;
import org.openhab.binding.freeboxos.internal.api.Response;
import org.openhab.binding.freeboxos.internal.api.Response.ErrorCode;

/**
Expand Down Expand Up @@ -52,7 +51,7 @@ public OpenSessionData(String appId, String appToken, String challenge) throws F
// Convert raw bytes to Hex
this.password = printHexBinary(rawHmac).toLowerCase();
} catch (IllegalArgumentException | NoSuchAlgorithmException | InvalidKeyException e) {
throw new FreeboxException("Error encoding session password", e, Response.of(ErrorCode.INVALID_TOKEN));
throw new FreeboxException(ErrorCode.INVALID_TOKEN, "Error encoding session password", e);
}
}

Expand Down
Loading

0 comments on commit 11adb0f

Please sign in to comment.