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

Commit 6718e4c

Browse files
authored
prepare 5.0.0-rc2 release (#194)
1 parent 9812c3a commit 6718e4c

File tree

66 files changed

+4073
-1676
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+4073
-1676
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
All notable changes to the LaunchDarkly Java SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
44

5+
## [5.0.0-rc2] - 2020-05-13
6+
The primary purpose of this second beta release is to introduce the new `DataSourceStatusProvider` API, which is the server-side equivalent to the "connection status" API that exists in LaunchDarkly's mobile SDKs. Other additions and changes since the previous beta release (5.0.0-rc1) are described below. See the [5.0.0-rc1 release notes](https://github.com/launchdarkly/java-server-sdk/releases/tag/5.0.0-rc1) for other changes since 4.13.0.
7+
8+
### Added:
9+
- `LDClient.getDataSourceStatusProvider()` is a status monitoring mechanism similar to `getDataStoreStatusProvider()`, but for the data source (streaming, polling, or file data). You can not only check the current connection status, but also choose to receive notifications when the status changes.
10+
- `LDConfig.Builder.logging()` is a new configuration category for options related to logging. Currently the only such option is `escalateDataSourceOutageLoggingAfter`, which controls the new connection failure logging behavior described below.
11+
- `LDConfig.Builder.threadPriority()` allows you to set the priority for worker threads created by the SDK.
12+
13+
### Changed:
14+
- Network failures and server errors for streaming or polling requests were previously logged at `ERROR` level in most cases but sometimes at `WARN` level. They are now all at `WARN` level, but with a new behavior: if connection failures continue without a successful retry for a certain amount of time, the SDK will log a special `ERROR`-level message to warn you that this is not just a brief outage. The amount of time is one minute by default, but can be changed with the new `logDataSourceOutageAsErrorAfter` option in `LoggingConfigurationBuilder`.
15+
- The number of worker threads maintained by the SDK has been reduced so that most intermittent background tasks, such as listener notifications, event flush timers, and polling requests, are now dispatched on a single thread. The delivery of analytics events to LaunchDarkly still has its own thread pool because it is a heavier-weight task with greater need for concurrency.
16+
- In polling mode, the poll requests previously ran on a dedicated worker thread that inherited its priority from the application thread that created the SDK. They are now on the SDK's main worker thread, which has `Thread.MIN_PRIORITY` by default (as all the other SDK threads already did) but the priority can be changed as described above.
17+
- Only relevant for implementing custom components: The `DataStore` and `DataSource` interfaces, and their factories, have been changed to provide a more general mechanism for status reporting. This does not affect the part of a persistent data store implementation that is database-specific, so new beta releases of the Consul/DynamoDB/Redis libraries were not necessary.
18+
519
## [5.0.0-rc1] - 2020-04-29
620
This beta release is being made available for testing and user feedback, due to the large number of changes from Java SDK 4.x. Features are still subject to change in the final 5.0.0 release. Until the final release, the beta source code will be on the [5.x branch](https://github.com/launchdarkly/java-server-sdk/tree/5.x). Javadocs can be found on [javadoc.io](https://javadoc.io/doc/com.launchdarkly/launchdarkly-server-sdk/5.0.0-rc1/index.html).
721

@@ -34,6 +48,13 @@ This is a major rewrite that introduces a cleaner API design, adds new features,
3448

3549
If you want to test this release and you are using Consul, DynamoDB, or Redis as a persistent data store, you will also need to update to version 2.0.0-rc1 of the [Consul integration](https://github.com/launchdarkly/java-server-sdk-consul/tree/2.x), 3.0.0-rc1 of the [DynamoDB integration](https://github.com/launchdarkly/java-server-sdk-dynamodb/tree/3.x), or 1.0.0-rc1 of the [Redis integration](http://github.com/launchdarkly/java-server-sdk-redis) (previously the Redis integration was built in; now it is a separate module).
3650

51+
## [4.14.0] - 2020-05-13
52+
### Added:
53+
- `EventSender` interface and `EventsConfigurationBuilder.eventSender()` allow you to specify a custom implementation of how event data is sent. This is mainly to facilitate testing, but could also be used to store and forward event data.
54+
55+
### Fixed:
56+
- Changed the Javadoc comments for the `LDClient` constructors to provide a better explanation of the client's initialization behavior.
57+
3758
## [4.13.0] - 2020-04-21
3859
### Added:
3960
- The new methods `Components.httpConfiguration()` and `LDConfig.Builder.http()`, and the new class `HttpConfigurationBuilder`, provide a subcomponent configuration model that groups together HTTP-related options such as `connectTimeoutMillis` and `proxyHost` - similar to how `Components.streamingDataSource()` works for streaming-related options or `Components.sendEvents()` for event-related options. The individual `LDConfig.Builder` methods for those options will still work, but are deprecated and will be removed in version 5.0.

build.gradle

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ ext.versions = [
7272
"guava": "28.2-jre",
7373
"jackson": "2.10.0",
7474
"launchdarklyJavaSdkCommon": "1.0.0-rc1",
75-
"okhttpEventsource": "2.1.0",
75+
"okhttpEventsource": "2.2.0",
7676
"slf4j": "1.7.21",
7777
"snakeyaml": "1.19",
7878
"jedis": "2.9.0"
@@ -326,11 +326,14 @@ def getFileFromClasspath(config, filePath) {
326326
}
327327

328328
def addOsgiManifest(jarTask, List<Configuration> importConfigs, List<Configuration> exportConfigs) {
329+
// For a prerelease build with "-beta", "-rc", etc., the prerelease qualifier has to be
330+
// removed from the bundle version because OSGi doesn't understand it.
331+
def implementationVersion = version.replaceFirst('-.*$', '')
329332
jarTask.manifest {
330333
attributes(
331-
"Implementation-Version": version,
334+
"Implementation-Version": implementationVersion,
332335
"Bundle-SymbolicName": "com.launchdarkly.sdk",
333-
"Bundle-Version": version,
336+
"Bundle-Version": implementationVersion,
334337
"Bundle-Name": "LaunchDarkly SDK",
335338
"Bundle-ManifestVersion": "2",
336339
"Bundle-Vendor": "LaunchDarkly"
@@ -351,7 +354,7 @@ def addOsgiManifest(jarTask, List<Configuration> importConfigs, List<Configurati
351354

352355
// Similarly, we're adding package exports for every package in whatever libraries we're
353356
// making publicly available.
354-
def sdkExports = getAllSdkPackages().collect { bundleExport(it, version) }
357+
def sdkExports = getAllSdkPackages().collect { bundleExport(it, implementationVersion) }
355358
def exportedDependencies = forEachArtifactAndVisiblePackage(exportConfigs, { a, p ->
356359
bundleExport(p, a.moduleVersion.id.version)
357360
})

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version=5.0.0-rc1
1+
version=5.0.0-rc2
22
# The following empty ossrh properties are used by LaunchDarkly's internal integration testing framework
33
# and should not be needed for typical development purposes (including by third-party developers).
44
ossrhUsername=

packaging-test/test-app/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ dependencies {
3636

3737
jar {
3838
bnd(
39+
// This consumer-policy directive completely turns off version checking for the test app's
40+
// OSGi imports, so for instance if the app uses version 2.x of package P, the import will
41+
// just be for p rather than p;version="[2.x,3)". One wouldn't normally do this, but we
42+
// need to be able to run the CI tests for snapshot/beta versions, and bnd does not handle
43+
// those correctly (5.0.0-beta1 will become "[5.0.0,6)" which will not work because the
44+
// beta is semantically *before* 5.0.0).
45+
'-consumer-policy': '',
3946
'Bundle-Activator': 'testapp.TestAppOsgiEntryPoint',
4047
'Import-Package': 'com.launchdarkly.sdk,com.launchdarkly.sdk.json' +
4148
',com.launchdarkly.sdk.server,org.slf4j' +

src/main/java/com/launchdarkly/sdk/server/ClientContextImpl.java

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,66 @@
22

33
import com.launchdarkly.sdk.server.interfaces.ClientContext;
44
import com.launchdarkly.sdk.server.interfaces.HttpConfiguration;
5+
import com.launchdarkly.sdk.server.interfaces.LoggingConfiguration;
56

7+
import java.util.concurrent.Executors;
8+
import java.util.concurrent.ScheduledExecutorService;
9+
10+
/**
11+
* This is the package-private implementation of {@link ClientContext} that contains additional non-public
12+
* SDK objects that may be used by our internal components.
13+
* <p>
14+
* All component factories, whether they are built-in ones or custom ones from the application, receive a
15+
* {@link ClientContext} and can access its public properties. But only our built-in ones can see the
16+
* package-private properties, which they can do by calling {@code ClientContextImpl.get(ClientContext)}
17+
* to make sure that what they have is really a {@code ClientContextImpl} (as opposed to some other
18+
* implementation of {@link ClientContext}, which might have been created for instance in application
19+
* test code).
20+
*/
621
final class ClientContextImpl implements ClientContext {
22+
private static volatile ScheduledExecutorService fallbackSharedExecutor = null;
23+
724
private final String sdkKey;
825
private final HttpConfiguration httpConfiguration;
26+
private final LoggingConfiguration loggingConfiguration;
927
private final boolean offline;
10-
private final DiagnosticAccumulator diagnosticAccumulator;
11-
private final DiagnosticEvent.Init diagnosticInitEvent;
12-
13-
ClientContextImpl(String sdkKey, LDConfig configuration, DiagnosticAccumulator diagnosticAccumulator) {
28+
private final int threadPriority;
29+
final ScheduledExecutorService sharedExecutor;
30+
final DiagnosticAccumulator diagnosticAccumulator;
31+
final DiagnosticEvent.Init diagnosticInitEvent;
32+
33+
private ClientContextImpl(
34+
String sdkKey,
35+
HttpConfiguration httpConfiguration,
36+
LoggingConfiguration loggingConfiguration,
37+
boolean offline,
38+
int threadPriority,
39+
ScheduledExecutorService sharedExecutor,
40+
DiagnosticAccumulator diagnosticAccumulator,
41+
DiagnosticEvent.Init diagnosticInitEvent
42+
) {
43+
this.sdkKey = sdkKey;
44+
this.httpConfiguration = httpConfiguration;
45+
this.loggingConfiguration = loggingConfiguration;
46+
this.offline = offline;
47+
this.threadPriority = threadPriority;
48+
this.sharedExecutor = sharedExecutor;
49+
this.diagnosticAccumulator = diagnosticAccumulator;
50+
this.diagnosticInitEvent = diagnosticInitEvent;
51+
}
52+
53+
ClientContextImpl(
54+
String sdkKey,
55+
LDConfig configuration,
56+
ScheduledExecutorService sharedExecutor,
57+
DiagnosticAccumulator diagnosticAccumulator
58+
) {
1459
this.sdkKey = sdkKey;
1560
this.httpConfiguration = configuration.httpConfig;
61+
this.loggingConfiguration = configuration.loggingConfig;
1662
this.offline = configuration.offline;
63+
this.threadPriority = configuration.threadPriority;
64+
this.sharedExecutor = sharedExecutor;
1765
if (!configuration.diagnosticOptOut && diagnosticAccumulator != null) {
1866
this.diagnosticAccumulator = diagnosticAccumulator;
1967
this.diagnosticInitEvent = new DiagnosticEvent.Init(diagnosticAccumulator.dataSinceDate, diagnosticAccumulator.diagnosticId, configuration);
@@ -37,28 +85,42 @@ public boolean isOffline() {
3785
public HttpConfiguration getHttpConfiguration() {
3886
return httpConfiguration;
3987
}
40-
41-
// Note that the following two properties are package-private - they are only used by SDK internal components,
42-
// not any custom components implemented by an application.
43-
DiagnosticAccumulator getDiagnosticAccumulator() {
44-
return diagnosticAccumulator;
88+
89+
@Override
90+
public LoggingConfiguration getLoggingConfiguration() {
91+
return loggingConfiguration;
4592
}
4693

47-
DiagnosticEvent.Init getDiagnosticInitEvent() {
48-
return diagnosticInitEvent;
94+
@Override
95+
public int getThreadPriority() {
96+
return threadPriority;
4997
}
5098

51-
static DiagnosticAccumulator getDiagnosticAccumulator(ClientContext context) {
99+
/**
100+
* This mechanism is a convenience for internal components to access the package-private fields of the
101+
* context if it is a ClientContextImpl, and to receive null values for those fields if it is not.
102+
* The latter case should only happen in application test code where the application developer has no
103+
* way to create our package-private ClientContextImpl. In that case, we also generate a temporary
104+
* sharedExecutor so components can work correctly in tests.
105+
*/
106+
static ClientContextImpl get(ClientContext context) {
52107
if (context instanceof ClientContextImpl) {
53-
return ((ClientContextImpl)context).getDiagnosticAccumulator();
108+
return (ClientContextImpl)context;
54109
}
55-
return null;
56-
}
57-
58-
static DiagnosticEvent.Init getDiagnosticInitEvent(ClientContext context) {
59-
if (context instanceof ClientContextImpl) {
60-
return ((ClientContextImpl)context).getDiagnosticInitEvent();
110+
synchronized (ClientContextImpl.class) {
111+
if (fallbackSharedExecutor == null) {
112+
fallbackSharedExecutor = Executors.newSingleThreadScheduledExecutor();
113+
}
61114
}
62-
return null;
115+
return new ClientContextImpl(
116+
context.getSdkKey(),
117+
context.getHttpConfiguration(),
118+
context.getLoggingConfiguration(),
119+
context.isOffline(),
120+
context.getThreadPriority(),
121+
fallbackSharedExecutor,
122+
null,
123+
null
124+
);
63125
}
64126
}

0 commit comments

Comments
 (0)