SDK: Fix link download release (#2273)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -289,39 +289,41 @@ public class MgmtTargetResource implements MgmtTargetRestApi {
|
|||||||
final MgmtActionConfirmationRequestBodyPut actionConfirmation) {
|
final MgmtActionConfirmationRequestBodyPut actionConfirmation) {
|
||||||
log.debug("updateActionConfirmation with data [targetId={}, actionId={}]: {}", targetId, actionId, actionConfirmation);
|
log.debug("updateActionConfirmation with data [targetId={}, actionId={}]: {}", targetId, actionId, actionConfirmation);
|
||||||
|
|
||||||
return getValidatedAction(targetId, actionId).map(action -> {
|
return getValidatedAction(targetId, actionId)
|
||||||
try {
|
.map(action -> {
|
||||||
switch (actionConfirmation.getConfirmation()) {
|
try {
|
||||||
case CONFIRMED:
|
switch (actionConfirmation.getConfirmation()) {
|
||||||
log.info("Confirmed the action (actionId: {}, targetId: {}) as we got {} report",
|
case CONFIRMED:
|
||||||
actionId, targetId, actionConfirmation.getConfirmation());
|
log.debug("Confirmed the action (actionId: {}, targetId: {}) as we got {} report",
|
||||||
confirmationManagement.confirmAction(actionId, actionConfirmation.getCode(), actionConfirmation.getDetails());
|
actionId, targetId, actionConfirmation.getConfirmation());
|
||||||
break;
|
confirmationManagement.confirmAction(actionId, actionConfirmation.getCode(), actionConfirmation.getDetails());
|
||||||
case DENIED:
|
break;
|
||||||
default:
|
case DENIED:
|
||||||
log.debug("Controller denied the action (actionId: {}, controllerId: {}) as we got {} report.",
|
default:
|
||||||
actionId, targetId, actionConfirmation.getConfirmation());
|
log.debug("Controller denied the action (actionId: {}, controllerId: {}) as we got {} report.",
|
||||||
confirmationManagement.denyAction(actionId, actionConfirmation.getCode(), actionConfirmation.getDetails());
|
actionId, targetId, actionConfirmation.getConfirmation());
|
||||||
break;
|
confirmationManagement.denyAction(actionId, actionConfirmation.getCode(), actionConfirmation.getDetails());
|
||||||
}
|
break;
|
||||||
return new ResponseEntity<Void>(HttpStatus.OK);
|
}
|
||||||
} catch (final InvalidConfirmationFeedbackException e) {
|
return new ResponseEntity<Void>(HttpStatus.OK);
|
||||||
if (e.getReason() == InvalidConfirmationFeedbackException.Reason.ACTION_CLOSED) {
|
} catch (final InvalidConfirmationFeedbackException e) {
|
||||||
log.warn("Updating action {} with confirmation {} not possible since action not active anymore.",
|
if (e.getReason() == InvalidConfirmationFeedbackException.Reason.ACTION_CLOSED) {
|
||||||
action.getId(), actionConfirmation.getConfirmation(), e);
|
log.warn("Updating action {} with confirmation {} not possible since action not active anymore.",
|
||||||
return new ResponseEntity<Void>(HttpStatus.GONE);
|
action.getId(), actionConfirmation.getConfirmation(), e);
|
||||||
} else if (e.getReason() == InvalidConfirmationFeedbackException.Reason.NOT_AWAITING_CONFIRMATION) {
|
return new ResponseEntity<Void>(HttpStatus.GONE);
|
||||||
log.debug("Action is not waiting for confirmation, deny request.", e);
|
} else if (e.getReason() == InvalidConfirmationFeedbackException.Reason.NOT_AWAITING_CONFIRMATION) {
|
||||||
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
|
log.debug("Action is not waiting for confirmation, deny request.", e);
|
||||||
} else {
|
return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
|
||||||
log.debug("Action confirmation failed with unknown reason.", e);
|
} else {
|
||||||
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
|
log.debug("Action confirmation failed with unknown reason.", e);
|
||||||
}
|
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}).orElseGet(() -> {
|
}
|
||||||
log.warn("Action {} not found for target {}", actionId, targetId);
|
})
|
||||||
return ResponseEntity.notFound().build();
|
.orElseGet(() -> {
|
||||||
});
|
log.warn("Action {} not found for target {}", actionId, targetId);
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
package org.eclipse.hawkbit.sdk;
|
package org.eclipse.hawkbit.sdk;
|
||||||
|
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -38,6 +39,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -66,6 +68,7 @@ import org.apache.hc.client5.http.impl.classic.HttpClients;
|
|||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||||
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
|
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
|
||||||
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
|
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
|
||||||
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.hc.core5.ssl.SSLContextBuilder;
|
import org.apache.hc.core5.ssl.SSLContextBuilder;
|
||||||
import org.springframework.hateoas.Link;
|
import org.springframework.hateoas.Link;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
@@ -146,11 +149,17 @@ public class HawkbitClient {
|
|||||||
return service(serviceType, tenantProperties, controller);
|
return service(serviceType, tenantProperties, controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads a link. If the returned type (linkType) is {@link ClassicHttpResponse} or {@link InputStream} then the caller is responsible
|
||||||
|
* to close the response. Otherwise, it is assumed and json object, it is deserialized and returned.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T getLink(final Link link, final Class<T> linkType, final Tenant tenant, final Controller controller) throws IOException {
|
public static <T> T getLink(final Link link, final Class<T> linkType, final Tenant tenant, final Controller controller) throws IOException {
|
||||||
final String url = link.getHref();
|
final String url = link.getHref();
|
||||||
final HttpClientKey key = new HttpClientKey(
|
final HttpClientKey key = new HttpClientKey(
|
||||||
url.startsWith("https://"), controller == null ? null : controller.getCertificate(), tenant.getTenantCA());
|
url.startsWith("https://"), controller == null ? null : controller.getCertificate(), tenant.getTenantCA());
|
||||||
final HttpClient httpClient = httpClient(key);
|
final HttpClient httpClient = httpClient(key);
|
||||||
|
final AtomicBoolean delegatedRelease = new AtomicBoolean(false);
|
||||||
try {
|
try {
|
||||||
final HttpGet request = new HttpGet(url);
|
final HttpGet request = new HttpGet(url);
|
||||||
final String gatewayToken = tenant.getGatewayToken();
|
final String gatewayToken = tenant.getGatewayToken();
|
||||||
@@ -168,17 +177,54 @@ public class HawkbitClient {
|
|||||||
throw new IllegalStateException("Unexpected status code: " + response.getCode());
|
throw new IllegalStateException("Unexpected status code: " + response.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linkType.isAssignableFrom(response.getClass())) {
|
if (linkType.isAssignableFrom(ClassicHttpResponse.class)) {
|
||||||
return (T)response;
|
delegatedRelease.set(true);
|
||||||
|
return (T)Proxy.newProxyInstance(
|
||||||
|
ClassicHttpResponse.class.getClassLoader(), new Class<?>[] { ClassicHttpResponse.class },
|
||||||
|
(proxy, method, args) -> {
|
||||||
|
if (ObjectUtils.isEmpty(method.getParameterTypes()) && method.getName().equals("close")) {
|
||||||
|
response.close();
|
||||||
|
key.release();
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return method.invoke(response, args);
|
||||||
|
} catch (final InvocationTargetException e) {
|
||||||
|
throw e.getCause() == null ? e : e.getCause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
} else if (linkType == InputStream.class) {
|
} else if (linkType == InputStream.class) {
|
||||||
return (T)response.getEntity().getContent();
|
final InputStream is = response.getEntity().getContent();
|
||||||
|
delegatedRelease.set(true);
|
||||||
|
return (T)new InputStream() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
return is.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(final byte[] b, final int off, final int read) throws IOException {
|
||||||
|
return is.read(b, off, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} finally {
|
||||||
|
key.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
return new ObjectMapper().readValue(response.getEntity().getContent(), linkType);
|
return new ObjectMapper().readValue(response.getEntity().getContent(), linkType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
synchronized (HTTP_CLIENTS) {
|
if (!delegatedRelease.get()) {
|
||||||
HTTP_CLIENTS.get(key).release();
|
key.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,11 +257,7 @@ public class HawkbitClient {
|
|||||||
.contract(contract)
|
.contract(contract)
|
||||||
.requestInterceptor(requestInterceptorFn.apply(tenant, controller))
|
.requestInterceptor(requestInterceptorFn.apply(tenant, controller))
|
||||||
.target(serviceType, url);
|
.target(serviceType, url);
|
||||||
CLEANER.register(service, () -> {
|
CLEANER.register(service, key::release);
|
||||||
synchronized (HTTP_CLIENTS) {
|
|
||||||
HTTP_CLIENTS.get(key).release();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,6 +488,12 @@ public class HawkbitClient {
|
|||||||
private final boolean https;
|
private final boolean https;
|
||||||
private final Certificate clientCertificate;
|
private final Certificate clientCertificate;
|
||||||
private final X509Certificate[] serverCertificates;
|
private final X509Certificate[] serverCertificates;
|
||||||
|
|
||||||
|
private void release() {
|
||||||
|
synchronized (HTTP_CLIENTS) {
|
||||||
|
HTTP_CLIENTS.get(this).release();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class HttpClientWrapper {
|
private static class HttpClientWrapper {
|
||||||
|
|||||||
Reference in New Issue
Block a user