Skip to content

Commit

Permalink
separated httpclient from module
Browse files Browse the repository at this point in the history
  • Loading branch information
Bilal Al committed Sep 11, 2024
1 parent 1e9482d commit bb87766
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 261 deletions.
12 changes: 6 additions & 6 deletions client/src/main/java/io/split/client/SplitClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.utils.FileTypeEnum;
import io.split.integrations.IntegrationsConfig;
import io.split.service.SplitHttpClient;
import io.split.service.CustomHttpModule;
import io.split.storages.enums.OperationMode;
import io.split.storages.enums.StorageMode;
import org.apache.hc.core5.http.HttpHost;
Expand Down Expand Up @@ -92,7 +92,7 @@ public class SplitClientConfig {
private final HashSet<String> _flagSetsFilter;
private final int _invalidSets;
private final CustomHeaderDecorator _customHeaderDecorator;
private final SplitHttpClient _alternativeHTTPModule;
private final CustomHttpModule _alternativeHTTPModule;

public static Builder builder() {
return new Builder();
Expand Down Expand Up @@ -150,7 +150,7 @@ private SplitClientConfig(String endpoint,
HashSet<String> flagSetsFilter,
int invalidSets,
CustomHeaderDecorator customHeaderDecorator,
SplitHttpClient alternativeHTTPModule) {
CustomHttpModule alternativeHTTPModule) {
_endpoint = endpoint;
_eventsEndpoint = eventsEndpoint;
_featuresRefreshRate = pollForFeatureChangesEveryNSeconds;
Expand Down Expand Up @@ -412,7 +412,7 @@ public CustomHeaderDecorator customHeaderDecorator() {
return _customHeaderDecorator;
}

public SplitHttpClient alternativeHTTPModule() { return _alternativeHTTPModule; }
public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; }
public static final class Builder {

private String _endpoint = SDK_ENDPOINT;
Expand Down Expand Up @@ -470,7 +470,7 @@ public static final class Builder {
private HashSet<String> _flagSetsFilter = new HashSet<>();
private int _invalidSetsCount = 0;
private CustomHeaderDecorator _customHeaderDecorator = null;
private SplitHttpClient _alternativeHTTPModule = null;
private CustomHttpModule _alternativeHTTPModule = null;

public Builder() {
}
Expand Down Expand Up @@ -971,7 +971,7 @@ public Builder customHeaderDecorator(CustomHeaderDecorator customHeaderDecorator
* @param alternativeHTTPModule
* @return this builder
*/
public Builder alternativeHTTPModule(SplitHttpClient alternativeHTTPModule) {
public Builder alternativeHTTPModule(CustomHttpModule alternativeHTTPModule) {
_alternativeHTTPModule = alternativeHTTPModule;
return this;
}
Expand Down
15 changes: 2 additions & 13 deletions client/src/main/java/io/split/client/SplitFactoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public class SplitFactoryImpl implements SplitFactory {
private RequestDecorator _requestDecorator;

// Constructor for standalone mode
public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyntaxException {
public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyntaxException, IOException {
_userStorageWrapper = null;
_operationMode = config.operationMode();
_startTime = System.currentTimeMillis();
Expand Down Expand Up @@ -193,10 +193,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
if (config.alternativeHTTPModule() == null) {
_splitHttpClient = buildSplitHttpClient(apiToken, config, _sdkMetadata, _requestDecorator);
} else {
_splitHttpClient = config.alternativeHTTPModule();
_splitHttpClient.setMetaData(_sdkMetadata);
_splitHttpClient.setRequestDecorator(_requestDecorator);
_splitHttpClient.setApiKey(apiToken);
_splitHttpClient = config.alternativeHTTPModule().createClient(apiToken, _sdkMetadata, _requestDecorator);
}

// Roots
Expand Down Expand Up @@ -284,14 +281,6 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
}
}

public RequestDecorator getRequestDecorator() {
return _requestDecorator;
}

public SDKMetadata getSDKMetaData() {
return _sdkMetadata;
}

// Constructor for consumer mode
protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStorageWrapper customStorageWrapper)
throws URISyntaxException {
Expand Down
13 changes: 13 additions & 0 deletions client/src/main/java/io/split/service/CustomHttpModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.split.service;

import io.split.client.RequestDecorator;
import io.split.client.utils.SDKMetadata;
import io.split.service.SplitHttpClient;

import java.io.IOException;

public interface CustomHttpModule {
public SplitHttpClient createClient(String apiToken, SDKMetadata sdkMetadata, RequestDecorator requestDecorator) throws IOException;


}
8 changes: 0 additions & 8 deletions client/src/main/java/io/split/service/SplitHttpClient.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package io.split.service;

import io.split.client.RequestDecorator;
import io.split.client.utils.SDKMetadata;
import io.split.engine.common.FetchOptions;
import io.split.client.dtos.SplitHttpResponse;

Expand Down Expand Up @@ -34,10 +32,4 @@ public interface SplitHttpClient extends Closeable {
public SplitHttpResponse post(URI uri,
HttpEntity entity,
Map<String, List<String>> additionalHeaders) throws IOException;

public void setMetaData(SDKMetadata metadata);

public void setRequestDecorator(RequestDecorator requestDecorator);

public void setApiKey(String apiKey);
}
15 changes: 0 additions & 15 deletions client/src/main/java/io/split/service/SplitHttpClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,4 @@ private void setBasicHeaders(HttpRequest request) {
public void close() throws IOException {
_client.close();
}

@Override
public void setMetaData(SDKMetadata metadata) {
// only implemented for Kerberos client
}

@Override
public void setRequestDecorator(RequestDecorator requestDecorator) {
// only implemented for Kerberos client
}
@Override
public void setApiKey(String apiKey) {
// only implemented for Kerberos client
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package io.split.httpmodules.okhttp;

import io.split.client.RequestDecorator;
import io.split.client.dtos.SplitHttpResponse;
import io.split.client.utils.SDKMetadata;
import io.split.engine.common.FetchOptions;
import io.split.service.SplitHttpClient;

import okhttp3.*;
import okhttp3.OkHttpClient.Builder;
import okhttp3.Request.*;
import okhttp3.logging.HttpLoggingInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import split.org.apache.hc.client5.http.classic.methods.HttpGet;
import split.org.apache.hc.core5.http.Header;
import split.org.apache.hc.core5.http.HttpEntity;
import split.org.apache.hc.core5.http.HttpRequest;
import split.org.apache.hc.core5.http.io.entity.EntityUtils;
import split.org.apache.hc.core5.http.message.BasicHeader;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class OkHttpClientImpl implements SplitHttpClient {
public final OkHttpClient httpClient;
private static final Logger _log = LoggerFactory.getLogger(OkHttpClientImpl.class);
private static final String HEADER_CACHE_CONTROL_NAME = "Cache-Control";
private static final String HEADER_CACHE_CONTROL_VALUE = "no-cache";
private static final String HEADER_API_KEY = "Authorization";
private static final String HEADER_CLIENT_KEY = "SplitSDKClientKey";
private static final String HEADER_CLIENT_MACHINE_NAME = "SplitSDKMachineName";
private static final String HEADER_CLIENT_MACHINE_IP = "SplitSDKMachineIP";
private static final String HEADER_CLIENT_VERSION = "SplitSDKVersion";
private RequestDecorator _requestDecorator;
private String _apikey;
private SDKMetadata _metadata;

public OkHttpClientImpl(String apiToken, SDKMetadata sdkMetadata, RequestDecorator requestDecorator,
Proxy proxy, String proxyAuthKerberosPrincipalName, boolean debugEnabled,
int readTimeout, int connectionTimeout) throws IOException {
_apikey = apiToken;
_metadata = sdkMetadata;
_requestDecorator = requestDecorator;

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
if (debugEnabled) {
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
} else {
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
}

Map<String, String> kerberosOptions = new HashMap<>();
kerberosOptions.put("com.sun.security.auth.module.Krb5LoginModule", "required");
kerberosOptions.put("refreshKrb5Config", "false");
kerberosOptions.put("doNotPrompt", "false");
kerberosOptions.put("useTicketCache", "true");

Authenticator proxyAuthenticator = getProxyAuthenticator(proxyAuthKerberosPrincipalName, kerberosOptions);

httpClient = new okhttp3.OkHttpClient.Builder()
.proxy(proxy)
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS)
.addInterceptor(logging)
.proxyAuthenticator(proxyAuthenticator)
.build();
}

public HTTPKerberosAuthInterceptor getProxyAuthenticator(String proxyKerberosPrincipalName,
Map<String, String> kerberosOptions) throws IOException {
return new HTTPKerberosAuthInterceptor(proxyKerberosPrincipalName, kerberosOptions);
}

@Override
public SplitHttpResponse get(URI uri, FetchOptions options, Map<String, List<String>> additionalHeaders) {
try {
okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder();
requestBuilder.url(uri.toString());
setBasicHeaders(requestBuilder);
setAdditionalAndDecoratedHeaders(requestBuilder, additionalHeaders);
if (options.cacheControlHeadersEnabled()) {
requestBuilder.addHeader(HEADER_CACHE_CONTROL_NAME, HEADER_CACHE_CONTROL_VALUE);
}

Request request = requestBuilder.build();
_log.debug(String.format("Request Headers: %s", request.headers()));

Response response = httpClient.newCall(request).execute();

int responseCode = response.code();

_log.debug(String.format("[GET] %s. Status code: %s",
request.url().toString(),
responseCode));

String statusMessage = "";
if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) {
_log.warn(String.format("Response status was: %s. Reason: %s", responseCode,
response.message()));
statusMessage = response.message();
}

String responseBody = response.body().string();
response.close();

return new SplitHttpResponse(responseCode,
statusMessage,
responseBody,
getResponseHeaders(response));
} catch (Exception e) {
throw new IllegalStateException(String.format("Problem in http get operation: %s", e), e);
}
}

@Override
public SplitHttpResponse post(URI url, HttpEntity entity,
Map<String, List<String>> additionalHeaders) {
try {
okhttp3.Request.Builder requestBuilder = getRequestBuilder();
requestBuilder.url(url.toString());
setBasicHeaders(requestBuilder);
setAdditionalAndDecoratedHeaders(requestBuilder, additionalHeaders);
requestBuilder.addHeader("Accept-Encoding", "gzip");
requestBuilder.addHeader("Content-Type", "application/json");
String post = EntityUtils.toString((HttpEntity) entity);
RequestBody postBody = RequestBody.create(post.getBytes());
requestBuilder.post(postBody);

Request request = getRequest(requestBuilder);
_log.debug(String.format("Request Headers: %s", request.headers()));

Response response = httpClient.newCall(request).execute();

int responseCode = response.code();

_log.debug(String.format("[GET] %s. Status code: %s",
request.url().toString(),
responseCode));

String statusMessage = "";
if (responseCode < HttpURLConnection.HTTP_OK || responseCode >= HttpURLConnection.HTTP_MULT_CHOICE) {
_log.warn(String.format("Response status was: %s. Reason: %s", responseCode,
response.message()));
statusMessage = response.message();
}
response.close();

return new SplitHttpResponse(responseCode, statusMessage, "", getResponseHeaders(response));
} catch (Exception e) {
throw new IllegalStateException(String.format("Problem in http post operation: %s", e), e);
}
}

protected okhttp3.Request.Builder getRequestBuilder() {
return new okhttp3.Request.Builder();
}

protected Request getRequest(okhttp3.Request.Builder requestBuilder) {
return requestBuilder.build();
}
protected void setBasicHeaders(okhttp3.Request.Builder requestBuilder) {
requestBuilder.addHeader(HEADER_API_KEY, "Bearer " + _apikey);
requestBuilder.addHeader(HEADER_CLIENT_VERSION, _metadata.getSdkVersion());
requestBuilder.addHeader(HEADER_CLIENT_MACHINE_IP, _metadata.getMachineIp());
requestBuilder.addHeader(HEADER_CLIENT_MACHINE_NAME, _metadata.getMachineName());
requestBuilder.addHeader(HEADER_CLIENT_KEY, _apikey.length() > 4
? _apikey.substring(_apikey.length() - 4)
: _apikey);
}

protected void setAdditionalAndDecoratedHeaders(okhttp3.Request.Builder requestBuilder, Map<String, List<String>> additionalHeaders) {
if (additionalHeaders != null) {
for (Map.Entry<String, List<String>> entry : additionalHeaders.entrySet()) {
for (String value : entry.getValue()) {
requestBuilder.addHeader(entry.getKey(), value);
}
}
}
HttpRequest request = new HttpGet("");
_requestDecorator.decorateHeaders(request);
for (Header header : request.getHeaders()) {
requestBuilder.addHeader(header.getName(), header.getValue());
}
}

protected Header[] getResponseHeaders(Response response) {
List<BasicHeader> responseHeaders = new ArrayList<>();
Map<String, List<String>> map = response.headers().toMultimap();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
if (entry.getKey() != null) {
BasicHeader responseHeader = new BasicHeader(entry.getKey(), entry.getValue());
responseHeaders.add(responseHeader);
}
}
return responseHeaders.toArray(new split.org.apache.hc.core5.http.Header[0]);
}
@Override
public void close() throws IOException {
httpClient.dispatcher().executorService().shutdown();
}

}
Loading

0 comments on commit bb87766

Please sign in to comment.