Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 08c0895

Browse files
authored
Merge pull request #3 from launchdarkly/drichelson/ch2310/java-sdk-does-not-allow-configuration-for
Remove apache http in favor of okhttp
2 parents 947c69e + a80e94c commit 08c0895

File tree

13 files changed

+172
-382
lines changed

13 files changed

+172
-382
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@
1414
build/
1515
bin/
1616
gradle.properties
17+
18+
classes/

build.gradle

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,18 @@ repositories {
1919

2020
allprojects {
2121
group = 'com.launchdarkly'
22-
version = "2.1.0"
22+
version = "2.2.0-SNAPSHOT"
2323
sourceCompatibility = 1.7
2424
targetCompatibility = 1.7
2525
}
2626

2727
dependencies {
28-
compile "org.apache.httpcomponents:httpclient:4.5.2"
29-
compile "org.apache.httpcomponents:httpclient-cache:4.5.2"
3028
compile "commons-codec:commons-codec:1.10"
3129
compile "com.google.code.gson:gson:2.7"
3230
compile "com.google.guava:guava:19.0"
3331
compile "joda-time:joda-time:2.9.3"
3432
compile "org.slf4j:slf4j-api:1.7.21"
35-
compile group: "com.launchdarkly", name: "okhttp-eventsource", version: "1.1.1", changing: true
33+
compile group: "com.launchdarkly", name: "okhttp-eventsource", version: "1.2.0-SNAPSHOT", changing: true
3634
compile "redis.clients:jedis:2.9.0"
3735
testCompile "org.easymock:easymock:3.4"
3836
testCompile 'junit:junit:4.12'

src/main/java/com/launchdarkly/client/EventProcessor.java

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package com.launchdarkly.client;
22

33
import com.google.common.util.concurrent.ThreadFactoryBuilder;
4-
import com.google.gson.Gson;
5-
import org.apache.http.client.config.RequestConfig;
6-
import org.apache.http.client.methods.CloseableHttpResponse;
7-
import org.apache.http.client.methods.HttpPost;
8-
import org.apache.http.entity.StringEntity;
9-
import org.apache.http.impl.client.CloseableHttpClient;
10-
import org.apache.http.impl.client.HttpClients;
4+
import okhttp3.MediaType;
5+
import okhttp3.Request;
6+
import okhttp3.RequestBody;
7+
import okhttp3.Response;
118
import org.slf4j.Logger;
129
import org.slf4j.LoggerFactory;
1310

@@ -58,19 +55,10 @@ public void flush() {
5855

5956
class Consumer implements Runnable {
6057
private final Logger logger = LoggerFactory.getLogger(Consumer.class);
61-
private final CloseableHttpClient client;
6258
private final LDConfig config;
6359

6460
Consumer(LDConfig config) {
6561
this.config = config;
66-
RequestConfig requestConfig = RequestConfig.custom()
67-
.setConnectTimeout(config.connectTimeout)
68-
.setSocketTimeout(config.socketTimeout)
69-
.setProxy(config.proxyHost)
70-
.build();
71-
client = HttpClients.custom()
72-
.setDefaultRequestConfig(requestConfig)
73-
.build();
7462
}
7563

7664
@Override
@@ -88,29 +76,28 @@ public void flush() {
8876
}
8977

9078
private void postEvents(List<Event> events) {
91-
CloseableHttpResponse response = null;
92-
Gson gson = new Gson();
93-
String json = gson.toJson(events);
79+
80+
String json = LDConfig.gson.toJson(events);
9481
logger.debug("Posting " + events.size() + " event(s) to " + config.eventsURI + " with payload: " + json);
9582

96-
HttpPost request = config.postEventsRequest(sdkKey, "/bulk");
97-
StringEntity entity = new StringEntity(json, "UTF-8");
98-
entity.setContentType("application/json");
99-
request.setEntity(entity);
83+
String content = LDConfig.gson.toJson(events);
10084

101-
try {
102-
response = client.execute(request);
103-
if (Util.handleResponse(logger, request, response)) {
104-
logger.debug("Successfully posted " + events.size() + " event(s).");
85+
Request request = config.getRequestBuilder(sdkKey)
86+
.url(config.eventsURI.toString() + "/bulk")
87+
.post(RequestBody.create(MediaType.parse("application/json; charset=utf-8"), content))
88+
.addHeader("Content-Type", "application/json")
89+
.build();
90+
91+
logger.debug("Posting " + events.size() + " event(s) using request: " + request);
92+
93+
try (Response response = config.httpClient.newCall(request).execute()) {
94+
if (!response.isSuccessful()) {
95+
logger.info("Got unexpected response when posting events: " + response);
96+
} else {
97+
logger.debug("Events Response: " + response.code());
10598
}
10699
} catch (IOException e) {
107-
logger.error("Unhandled exception in LaunchDarkly client attempting to connect to URI: " + config.eventsURI, e);
108-
} finally {
109-
try {
110-
if (response != null) response.close();
111-
} catch (IOException e) {
112-
logger.error("Unhandled exception in LaunchDarkly client", e);
113-
}
100+
logger.info("Unhandled exception in LaunchDarkly client when posting events to URL: " + request.url(), e);
114101
}
115102
}
116103
}

src/main/java/com/launchdarkly/client/FeatureFlag.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.launchdarkly.client;
22

3-
import com.google.gson.Gson;
43
import com.google.gson.JsonElement;
54
import com.google.gson.reflect.TypeToken;
65
import org.slf4j.Logger;
@@ -14,7 +13,6 @@
1413
class FeatureFlag {
1514
private final static Logger logger = LoggerFactory.getLogger(FeatureFlag.class);
1615

17-
private static final Gson gson = new Gson();
1816
private static final Type mapType = new TypeToken<Map<String, FeatureFlag>>() {
1917
}.getType();
2018

@@ -31,11 +29,11 @@ class FeatureFlag {
3129
private final boolean deleted;
3230

3331
static FeatureFlag fromJson(String json) {
34-
return gson.fromJson(json, FeatureFlag.class);
32+
return LDConfig.gson.fromJson(json, FeatureFlag.class);
3533
}
3634

3735
static Map<String, FeatureFlag> fromJsonMap(String json) {
38-
return gson.fromJson(json, mapType);
36+
return LDConfig.gson.fromJson(json, mapType);
3937
}
4038

4139
FeatureFlag(String key, int version, boolean on, List<Prerequisite> prerequisites, String salt, List<Target> targets, List<Rule> rules, VariationOrRollout fallthrough, Integer offVariation, List<JsonElement> variations, boolean deleted) {
Lines changed: 30 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,58 @@
11
package com.launchdarkly.client;
22

3-
import org.apache.http.client.cache.CacheResponseStatus;
4-
import org.apache.http.client.cache.HttpCacheContext;
5-
import org.apache.http.client.config.RequestConfig;
6-
import org.apache.http.client.methods.CloseableHttpResponse;
7-
import org.apache.http.client.methods.HttpGet;
8-
import org.apache.http.impl.client.CloseableHttpClient;
9-
import org.apache.http.impl.client.cache.CacheConfig;
10-
import org.apache.http.impl.client.cache.CachingHttpClients;
11-
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
12-
import org.apache.http.util.EntityUtils;
3+
import okhttp3.Request;
4+
import okhttp3.Response;
135
import org.slf4j.Logger;
146
import org.slf4j.LoggerFactory;
157

168
import java.io.IOException;
179
import java.util.Map;
1810

1911
class FeatureRequestor {
20-
21-
public static final String GET_LATEST_FLAGS_PATH = "/sdk/latest-flags";
12+
private static final Logger logger = LoggerFactory.getLogger(FeatureRequestor.class);
13+
private static final String GET_LATEST_FLAGS_PATH = "/sdk/latest-flags";
2214
private final String sdkKey;
2315
private final LDConfig config;
24-
private final CloseableHttpClient client;
25-
private static final Logger logger = LoggerFactory.getLogger(FeatureRequestor.class);
2616

2717
FeatureRequestor(String sdkKey, LDConfig config) {
2818
this.sdkKey = sdkKey;
2919
this.config = config;
30-
this.client = createClient();
31-
}
32-
33-
protected CloseableHttpClient createClient() {
34-
CloseableHttpClient client;
35-
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
36-
manager.setMaxTotal(100);
37-
manager.setDefaultMaxPerRoute(20);
38-
39-
CacheConfig cacheConfig = CacheConfig.custom()
40-
.setMaxCacheEntries(1000)
41-
.setMaxObjectSize(131072)
42-
.setSharedCache(false)
43-
.build();
44-
45-
RequestConfig requestConfig = RequestConfig.custom()
46-
.setConnectTimeout(config.connectTimeout)
47-
.setSocketTimeout(config.socketTimeout)
48-
.setProxy(config.proxyHost)
49-
.build();
50-
client = CachingHttpClients.custom()
51-
.setCacheConfig(cacheConfig)
52-
.setConnectionManager(manager)
53-
.setDefaultRequestConfig(requestConfig)
54-
.build();
55-
return client;
5620
}
5721

5822
Map<String, FeatureFlag> getAllFlags() throws IOException {
59-
HttpCacheContext context = HttpCacheContext.create();
60-
61-
HttpGet request = config.getRequest(sdkKey, GET_LATEST_FLAGS_PATH);
62-
63-
CloseableHttpResponse response = null;
64-
try {
65-
logger.debug("Making request: " + request);
66-
response = client.execute(request, context);
67-
68-
logCacheResponse(context.getCacheResponseStatus());
69-
if (!Util.handleResponse(logger, request, response)) {
70-
throw new IOException("Failed to fetch flags");
71-
}
72-
73-
String json = EntityUtils.toString(response.getEntity());
74-
logger.debug("Got response: " + response.toString());
75-
return FeatureFlag.fromJsonMap(json);
76-
}
77-
finally {
78-
try {
79-
if (response != null) response.close();
80-
} catch (IOException ignored) {
81-
}
82-
}
23+
String body = get(GET_LATEST_FLAGS_PATH);
24+
return FeatureFlag.fromJsonMap(body);
8325
}
8426

85-
void logCacheResponse(CacheResponseStatus status) {
86-
switch (status) {
87-
case CACHE_HIT:
88-
logger.debug("A response was generated from the cache with " +
89-
"no requests sent upstream");
90-
break;
91-
case CACHE_MODULE_RESPONSE:
92-
logger.debug("The response was generated directly by the " +
93-
"caching module");
94-
break;
95-
case CACHE_MISS:
96-
logger.debug("The response came from an upstream server");
97-
break;
98-
case VALIDATED:
99-
logger.debug("The response was generated from the cache " +
100-
"after validating the entry with the origin server");
101-
break;
102-
}
27+
FeatureFlag getFlag(String featureKey) throws IOException {
28+
String body = get(GET_LATEST_FLAGS_PATH + "/" + featureKey);
29+
return FeatureFlag.fromJson(body);
10330
}
10431

105-
FeatureFlag getFlag(String featureKey) throws IOException {
106-
HttpCacheContext context = HttpCacheContext.create();
107-
HttpGet request = config.getRequest(sdkKey, GET_LATEST_FLAGS_PATH + "/" + featureKey);
108-
CloseableHttpResponse response = null;
109-
try {
110-
response = client.execute(request, context);
32+
private String get(String path) throws IOException {
33+
Request request = config.getRequestBuilder(sdkKey)
34+
.url(config.baseURI.toString() + path)
35+
.get()
36+
.build();
11137

112-
logCacheResponse(context.getCacheResponseStatus());
38+
logger.debug("Making request: " + request);
11339

114-
if (!Util.handleResponse(logger, request, response)) {
115-
throw new IOException("Failed to fetch flag");
116-
}
117-
return FeatureFlag.fromJson(EntityUtils.toString(response.getEntity()));
118-
}
119-
finally {
120-
try {
121-
if (response != null) response.close();
122-
} catch (IOException ignored) {
40+
try (Response response = config.httpClient.newCall(request).execute()) {
41+
String body = response.body().string();
42+
43+
if (!response.isSuccessful()) {
44+
if (response.code() == 401) {
45+
logger.error("[401] Invalid SDK key when accessing URI: " + request.url());
46+
}
47+
throw new IOException("Unexpected response when retrieving Feature Flag(s): " + response + " using url: "
48+
+ request.url() + " with body: " + body);
12349
}
50+
logger.debug("Get flag(s) response: " + response.toString() + " with body: " + body);
51+
logger.debug("Cache hit count: " + config.httpClient.cache().hitCount() + " Cache network Count: " + config.httpClient.cache().networkCount());
52+
logger.debug("Cache response: " + response.cacheResponse());
53+
logger.debug("Network response: " + response.networkResponse());
54+
55+
return body;
12456
}
12557
}
12658
}

src/main/java/com/launchdarkly/client/LDClient.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.google.gson.JsonElement;
66
import com.google.gson.JsonPrimitive;
77
import org.apache.commons.codec.binary.Hex;
8-
import org.apache.http.annotation.ThreadSafe;
98
import org.slf4j.Logger;
109
import org.slf4j.LoggerFactory;
1110

@@ -28,11 +27,10 @@
2827
* A client for the LaunchDarkly API. Client instances are thread-safe. Applications should instantiate
2928
* a single {@code LDClient} for the lifetime of their application.
3029
*/
31-
@ThreadSafe
3230
public class LDClient implements LDClientInterface {
3331
private static final Logger logger = LoggerFactory.getLogger(LDClient.class);
3432
private static final String HMAC_ALGORITHM = "HmacSHA256";
35-
protected static final String CLIENT_VERSION = getClientVersion();
33+
static final String CLIENT_VERSION = getClientVersion();
3634

3735
private final LDConfig config;
3836
private final String sdkKey;

0 commit comments

Comments
 (0)