All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.cdap.delta.store.AssessmentServiceClient Maven / Gradle / Ivy
/*
* Copyright © 2021 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.cdap.delta.store;
import com.google.common.io.ByteStreams;
import com.google.gson.Gson;
import io.cdap.cdap.api.ServiceDiscoverer;
import io.cdap.cdap.api.retry.RetryableException;
import io.cdap.delta.app.service.AssessmentService;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.FailsafeExecutor;
import net.jodah.failsafe.RetryPolicy;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import javax.annotation.Nullable;
import javax.ws.rs.HttpMethod;
/**
* Class to handle Api calls to System Service
*/
public class AssessmentServiceClient {
private final ServiceDiscoverer serviceDiscoverer;
private final RetryPolicy retryPolicy;
private static final Gson GSON = new Gson();
private static final String SERVICE_NAME = "State Store (AssessorService)";
public AssessmentServiceClient(ServiceDiscoverer context) {
this.serviceDiscoverer = context;
retryPolicy = new RetryPolicy()
.withMaxAttempts(3)
.withMaxDuration(Duration.of(10, ChronoUnit.SECONDS))
.withDelay(Duration.of(200, ChronoUnit.MILLIS))
.withJitter(0.20D);
}
// Api calls to deal directly with byte[]
public byte[] retryableApiCall(String connectionUrl, String method, @Nullable byte[] requestBody) {
FailsafeExecutor failsafe = Failsafe.with(retryPolicy);
return failsafe.get(() -> executeCall(getHttpUrlConnection(connectionUrl), method, requestBody));
}
public byte[] retryableApiCall(String connectionUrl, String method) {
return retryableApiCall(connectionUrl, method, new byte[0]);
}
private byte[] executeCall(HttpURLConnection urlConn, String method, @Nullable byte[] body) throws IOException {
urlConn.setRequestMethod(method);
//Set request body if body is not null
if (!method.equals(HttpMethod.GET) && body != null) {
urlConn.setDoOutput(true);
try (OutputStream os = urlConn.getOutputStream()) {
os.write(body);
}
}
return retrieve(urlConn);
}
private byte[] retrieve(HttpURLConnection urlConn) throws IOException {
checkResponseCode(urlConn);
try (InputStream inputStream = urlConn.getInputStream()) {
return ByteStreams.toByteArray(inputStream);
} finally {
urlConn.disconnect();
}
}
// Api calls to deal with Objects
public T retryableApiCall(String connectionUrl, String method, @Nullable String requestBody,
@Nullable Type type) {
FailsafeExecutor failsafe = Failsafe.with(retryPolicy);
return failsafe.get(() -> executeCall(getHttpUrlConnection(connectionUrl), method, requestBody, type));
}
public T retryableApiCall(String connectionUrl, String method, Type type) {
return retryableApiCall(connectionUrl, method, null, type);
}
public void retryableApiCall(String connectionUrl, String method, @Nullable String requestBody) {
retryableApiCall(connectionUrl, method, requestBody, null);
}
private T executeCall(HttpURLConnection urlConn, String method, @Nullable String body, Type type)
throws IOException {
urlConn.setRequestMethod(method);
if (body != null) {
urlConn.setDoOutput(true);
try (OutputStreamWriter osw = new OutputStreamWriter(urlConn.getOutputStream(), StandardCharsets.UTF_8)) {
osw.write(body);
}
}
return retrieve(urlConn, type);
}
private T retrieve(HttpURLConnection urlConn, @Nullable Type type) throws IOException {
checkResponseCode(urlConn);
// type is null means it is a POST/PUT call with body to be updated.
// No particular response is expected
// The "checkResponseCode" method ensures the status code to be HttpURLConnection.HTTP_OK.
if (type == null) {
urlConn.disconnect();
return (T) Integer.valueOf(HttpURLConnection.HTTP_OK);
}
try (InputStreamReader reader = new InputStreamReader(urlConn.getInputStream(), StandardCharsets.UTF_8)) {
return GSON.fromJson(reader, type);
} finally {
urlConn.disconnect();
}
}
private void checkResponseCode(HttpURLConnection urlConn) throws IOException {
int responseCode = urlConn.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new RetryableException("Failed to call " + SERVICE_NAME + " service with status " + responseCode + ": " +
getError(urlConn));
}
}
// Returns the full content of the error stream for the given {@link HttpURLConnection}.
private String getError(HttpURLConnection urlConn) {
try (InputStream is = urlConn.getErrorStream()) {
if (is == null) {
return "Unknown error";
}
return new String(ByteStreams.toByteArray(is), StandardCharsets.UTF_8);
} catch (IOException e) {
return "Unknown error due to failure to read from error output: " + e.getMessage();
}
}
// A connection object is created with the given System Service paths and parameters
private HttpURLConnection getHttpUrlConnection(String methodPath) throws IOException {
HttpURLConnection connectionUrl = serviceDiscoverer.openConnection("system",
"delta",
AssessmentService.NAME,
methodPath);
if (connectionUrl == null) {
throw new RetryableException(SERVICE_NAME + " service is not available");
}
return connectionUrl;
}
}