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

Commit 9545fb5

Browse files
prepare 5.0.0 release (#195)
1 parent 5274931 commit 9545fb5

File tree

307 files changed

+23420
-22720
lines changed

Some content is hidden

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

307 files changed

+23420
-22720
lines changed

.circleci/config.yml

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ workflows:
2525
- test-linux:
2626
name: Java 11 - Linux - OpenJDK
2727
docker-image: circleci/openjdk:11
28+
with-coverage: true
2829
requires:
2930
- build-linux
3031
- packaging:
3132
requires:
3233
- build-linux
34+
- benchmarks:
35+
requires:
36+
- build-linux
3337
- build-test-windows:
3438
name: Java 11 - Windows - OpenJDK
3539

@@ -52,26 +56,44 @@ jobs:
5256
parameters:
5357
docker-image:
5458
type: string
59+
with-coverage:
60+
type: boolean
61+
default: false
5562
docker:
5663
- image: <<parameters.docker-image>>
57-
- image: redis
5864
steps:
5965
- checkout
6066
- run: cp gradle.properties.example gradle.properties
6167
- attach_workspace:
6268
at: build
6369
- run: java -version
64-
- run: ./gradlew test
70+
- run:
71+
name: Run tests
72+
command: ./gradlew test
73+
- when:
74+
condition: <<parameters.with-coverage>>
75+
steps:
76+
- run:
77+
name: Generate test coverage report
78+
command: |
79+
./gradlew jacocoTestReport
80+
mkdir -p coverage/
81+
cp -r build/reports/jacoco/test/* ./coverage
6582
- run:
6683
name: Save test results
6784
command: |
68-
mkdir -p ~/junit/;
85+
mkdir -p ~/junit/
6986
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \;
7087
when: always
7188
- store_test_results:
7289
path: ~/junit
7390
- store_artifacts:
7491
path: ~/junit
92+
- when:
93+
condition: <<parameters.with-coverage>>
94+
steps:
95+
- store_artifacts:
96+
path: coverage
7597

7698
build-test-windows:
7799
executor:
@@ -85,18 +107,6 @@ jobs:
85107
$ProgressPreference = "SilentlyContinue" # prevents console errors from CircleCI host
86108
iwr -outf openjdk.msi https://developers.redhat.com/download-manager/file/java-11-openjdk-11.0.5.10-2.windows.redhat.x86_64.msi
87109
Start-Process msiexec.exe -Wait -ArgumentList '/I openjdk.msi /quiet'
88-
- run:
89-
name: start Redis
90-
command: |
91-
$ProgressPreference = "SilentlyContinue"
92-
iwr -outf redis.zip https://github.com/MicrosoftArchive/redis/releases/download/win-3.0.504/Redis-x64-3.0.504.zip
93-
mkdir redis
94-
Expand-Archive -Path redis.zip -DestinationPath redis
95-
cd redis
96-
.\redis-server --service-install
97-
.\redis-server --service-start
98-
Start-Sleep -s 5
99-
.\redis-cli ping
100110
- run:
101111
name: build and test
102112
command: |
@@ -131,3 +141,19 @@ jobs:
131141
- run:
132142
name: run packaging tests
133143
command: cd packaging-test && make all
144+
145+
benchmarks:
146+
docker:
147+
- image: circleci/openjdk:11
148+
steps:
149+
- run: java -version
150+
- run: sudo apt-get install make -y -q
151+
- checkout
152+
- attach_workspace:
153+
at: build
154+
- run: cat gradle.properties.example >>gradle.properties
155+
- run:
156+
name: run benchmarks
157+
command: cd benchmarks && make
158+
- store_artifacts:
159+
path: benchmarks/build/reports/jmh

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ out/
1717
classes/
1818

1919
packaging-test/temp/
20+
benchmarks/lib/

.ldrelease/config.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ publications:
1010

1111
template:
1212
name: gradle
13-
env:
14-
LD_SKIP_DATABASE_TESTS: 1
13+
14+
releasableBranches:
15+
- name: master
16+
description: 5.x
17+
- name: 4.x
1518

1619
documentation:
1720
githubPages: true

CONTRIBUTING.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
Contributing to the LaunchDarkly Server-side SDK for Java
2-
================================================
1+
# Contributing to the LaunchDarkly Server-side SDK for Java
32

43
LaunchDarkly has published an [SDK contributor's guide](https://docs.launchdarkly.com/docs/sdk-contributors-guide) that provides a detailed explanation of how our SDKs work. See below for additional information on how to contribute to this SDK.
54

@@ -15,8 +14,10 @@ We encourage pull requests and other contributions from the community. Before su
1514

1615
### Prerequisites
1716

18-
The SDK builds with [Gradle](https://gradle.org/) and should be built against Java 7.
19-
17+
The SDK builds with [Gradle](https://gradle.org/) and should be built against Java 8.
18+
19+
Many basic classes are implemented in the module `launchdarkly-java-sdk-common`, whose source code is in the [`launchdarkly/java-sdk-common`](https://github.com/launchdarkly/java-sdk-common) repository; this is so the common code can be shared with the LaunchDarkly Android SDK. By design, the LaunchDarkly Java SDK distribution does not expose a dependency on that module; instead, its classes and Javadoc content are embedded in the SDK jars.
20+
2021
### Building
2122

2223
To build the SDK without running any tests:
@@ -41,4 +42,28 @@ To build the SDK and run all unit tests:
4142
./gradlew test
4243
```
4344

44-
By default, the full unit test suite includes live tests of the Redis integration. Those tests expect you to have Redis running locally. To skip them, set the environment variable `LD_SKIP_DATABASE_TESTS=1` before running the tests.
45+
### Benchmarks
46+
47+
The project in the `benchmarks` subdirectory uses [JMH](https://openjdk.java.net/projects/code-tools/jmh/) to generate performance metrics for the SDK. This is run as a CI job, and can also be run manually by running `make` within `benchmarks` and then inspecting `build/reports/jmh`.
48+
49+
## Coding best practices
50+
51+
### Logging
52+
53+
Currently the SDK uses SLF4J for all log output. Here some things to keep in mind for good logging behavior:
54+
55+
1. Stick to the standardized logger name scheme defined in `Loggers.java`, preferably for all log output, but definitely for all log output above `DEBUG` level. Logger names can be useful for filtering log output, so it is desirable for users to be able to reference a clear, stable logger name like `com.launchdarkly.sdk.server.LDClient.Events` rather than a class name like `com.launchdarkly.sdk.server.EventSummarizer` which is an implementation detail. The text of a log message should be distinctive enough that we can easily find which class generated the message.
56+
57+
2. Use parameterized messages (`Logger.MAIN.info("The value is {}", someValue)`) rather than string concatenation (`Logger.MAIN.info("The value is " + someValue)`). This avoids the overhead of string concatenation if the logger is not enabled for that level. If computing the value is an expensive operation, and it is _only_ relevant for logging, consider implementing that computation via a custom `toString()` method on some wrapper type so that it will be done lazily only if the log level is enabled.
58+
59+
3. Exception stacktraces should only be logged at debug level. For instance: `Logger.MAIN.warn("An error happened: {}", ex.toString()); Logger.MAIN.debug(ex.toString(), ex)`. Also, consider whether the stacktrace would be at all meaningful in this particular context; for instance, in a `try` block around a network I/O operation, the stacktrace would only tell us (a) some internal location in Java standard libraries and (b) the location in our own code where we tried to do the operation; (a) is very unlikely to tell us anything that the exception's type and message doesn't already tell us, and (b) could be more clearly communicated by just writing a specific log message.
60+
61+
### Code coverage
62+
63+
It is important to keep unit test coverage as close to 100% as possible in this project. You can view the latest code coverage report in CircleCI, as `coverage/html/index.html` in the artifacts for the "Java 11 - Linux - OpenJDK" job. You can also run the report locally with `./gradlew jacocoTestCoverage` and view `./build/reports/jacoco/test`. _The CircleCI build will fail if you commit a change that increases the number of uncovered lines_, unless you explicitly add an override as shown below.
64+
65+
Sometimes a gap in coverage is unavoidable, usually because the compiler requires us to provide a code path for some condition that in practice can't happen and can't be tested, or because of a known issue with the code coverage tool. Please handle all such cases as follows:
66+
67+
* Mark the code with an explanatory comment beginning with "COVERAGE:".
68+
* Run the code coverage task with `./gradlew jacocoTestCoverageVerification`. It should fail and indicate how many lines of missed coverage exist in the method you modified.
69+
* Add an item in the `knownMissedLinesForMethods` map in `build.gradle` that specifies that number of missed lines for that method signature. For instance, if the method `com.launchdarkly.sdk.server.SomeClass.someMethod(java.lang.String)` has two missed lines that cannot be covered, you would add `"SomeClass.someMethod(java.lang.String)": 2`.

README.md

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,61 @@
1-
LaunchDarkly Server-side SDK for Java
2-
=========================
1+
# LaunchDarkly Server-side SDK for Java
32

43
[![Circle CI](https://circleci.com/gh/launchdarkly/java-server-sdk.svg?style=shield)](https://circleci.com/gh/launchdarkly/java-server-sdk)
54
[![Javadocs](http://javadoc.io/badge/com.launchdarkly/launchdarkly-java-server-sdk.svg)](http://javadoc.io/doc/com.launchdarkly/launchdarkly-java-server-sdk)
65

7-
LaunchDarkly overview
8-
-------------------------
6+
## LaunchDarkly overview
7+
98
[LaunchDarkly](https://www.launchdarkly.com) is a feature management platform that serves over 100 billion feature flags daily to help teams build better software, faster. [Get started](https://docs.launchdarkly.com/docs/getting-started) using LaunchDarkly today!
109

1110
[![Twitter Follow](https://img.shields.io/twitter/follow/launchdarkly.svg?style=social&label=Follow&maxAge=2592000)](https://twitter.com/intent/follow?screen_name=launchdarkly)
1211

13-
Supported Java versions
14-
-----------------------
12+
## Supported Java versions
1513

16-
This version of the LaunchDarkly SDK works with Java 7 and above.
14+
This version of the LaunchDarkly SDK works with Java 8 and above.
1715

18-
Distributions
19-
-------------
16+
## Distributions
2017

2118
Three variants of the SDK jar are published to Maven:
2219

23-
* The default uberjar - this is accessible as `com.launchdarkly:launchdarkly-java-server-sdk:jar` and is the dependency used in the "[Getting started](https://docs.launchdarkly.com/docs/java-sdk-reference#section-getting-started)" section of the SDK reference guide as well as in the [`hello-java`](https://github.com/launchdarkly/hello-java) sample app. This variant contains the SDK classes, and all of the SDK's dependencies except for Gson and SLF4J, which must be provided by the host application. The bundled dependencies have shaded package names (and are not exported in OSGi), so they will not interfere with any other versions of the same packages.
24-
* The extended uberjar - add `<classifier>all</classifier>` in Maven, or `:all` in Gradle. This is the same as the default uberjar except that Gson and SLF4J are also bundled, without shading (and are exported in OSGi).
20+
* The default uberjar - this is accessible as `com.launchdarkly:launchdarkly-java-server-sdk:jar` and is the dependency used in the "[Getting started](https://docs.launchdarkly.com/docs/java-sdk-reference#section-getting-started)" section of the SDK reference guide as well as in the [`hello-java`](https://github.com/launchdarkly/hello-java) sample app. This variant contains the SDK classes, and all of the SDK's dependencies except for SLF4J, which must be provided by the host application. The bundled dependencies have shaded package names (and are not exported in OSGi), so they will not interfere with any other versions of the same packages.
21+
* The extended uberjar - add `<classifier>all</classifier>` in Maven, or `:all` in Gradle. This is the same as the default uberjar except that SLF4J is also bundled, without shading (and is exported in OSGi).
2522
* The "thin" jar - add `<classifier>thin</classifier>` in Maven, or `:thin` in Gradle. This contains _only_ the SDK classes.
2623

27-
Getting started
28-
-----------
24+
## Getting started
2925

3026
Refer to the [SDK reference guide](https://docs.launchdarkly.com/docs/java-sdk-reference#section-getting-started) for instructions on getting started with using the SDK.
3127

32-
Logging
33-
-------
28+
## Logging
3429

3530
The LaunchDarkly SDK uses [SLF4J](https://www.slf4j.org/). All loggers are namespaced under `com.launchdarkly`. For an example configuration check out the [hello-java](https://github.com/launchdarkly/hello-java) project.
3631

3732
Be aware of two considerations when enabling the DEBUG log level:
3833
1. Debug-level logs can be very verbose. It is not recommended that you turn on debug logging in high-volume environments.
3934
1. Potentially sensitive information is logged including LaunchDarkly users created by you in your usage of this SDK.
4035

41-
Using flag data from a file
42-
---------------------------
36+
## Using flag data from a file
4337

4438
For testing purposes, the SDK can be made to read feature flag state from a file or files instead of connecting to LaunchDarkly. See <a href="http://javadoc.io/page/com.launchdarkly/launchdarkly-java-server-sdk/latest/com/launchdarkly/client/files/FileComponents.html">FileComponents</a> for more details.
4539

46-
DNS caching issues
47-
------------------
40+
## DNS caching issues
4841

4942
LaunchDarkly servers operate in a load-balancing framework which may cause their IP addresses to change. This could result in the SDK failing to connect to LaunchDarkly if an old IP address is still in your system's DNS cache.
5043

5144
Unlike some other languages, in Java the DNS caching behavior is controlled by the Java virtual machine rather than the operating system. The default behavior varies depending on whether there is a [security manager](https://docs.oracle.com/javase/tutorial/essential/environment/security.html): if there is, IP addresses will _never_ expire. In that case, we recommend that you set the security property `networkaddress.cache.ttl`, as described [here](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-jvm-ttl.html), to a number of seconds such as 30 or 60 (a lower value will reduce the chance of intermittent failures, but will slightly reduce networking performance).
5245

53-
Learn more
54-
----------
46+
## Learn more
5547

5648
Check out our [documentation](https://docs.launchdarkly.com) for in-depth instructions on configuring and using LaunchDarkly. You can also head straight to the [complete reference guide for this SDK](https://docs.launchdarkly.com/docs/java-sdk-reference) or our [code-generated API documentation](https://launchdarkly.github.io/java-server-sdk/).
5749

58-
Testing
59-
-------
50+
## Testing
6051

6152
We run integration tests for all our SDKs using a centralized test harness. This approach gives us the ability to test for consistency across SDKs, as well as test networking behavior in a long-running application. These tests cover each method in the SDK, and verify that event sending, flag evaluation, stream reconnection, and other aspects of the SDK all behave correctly.
6253

63-
Contributing
64-
------------
54+
## Contributing
6555

6656
We encourage pull requests and other contributions from the community. Check out our [contributing guidelines](CONTRIBUTING.md) for instructions on how to contribute to this SDK.
6757

68-
About LaunchDarkly
69-
-----------
58+
## About LaunchDarkly
7059

7160
* LaunchDarkly is a continuous delivery platform that provides feature flags as a service and allows developers to iterate quickly and safely. We allow you to easily flag your features and manage them from the LaunchDarkly dashboard. With LaunchDarkly, you can:
7261
* Roll out a new feature to a subset of your users (like a group of users who opt-in to a beta tester group), gathering feedback and bug reports from real-world use cases.

benchmarks/Makefile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.PHONY: benchmark clean sdk
2+
3+
BASE_DIR:=$(shell pwd)
4+
PROJECT_DIR=$(shell cd .. && pwd)
5+
SDK_VERSION=$(shell grep "version=" $(PROJECT_DIR)/gradle.properties | cut -d '=' -f 2)
6+
7+
BENCHMARK_ALL_JAR=lib/launchdarkly-java-server-sdk-all.jar
8+
BENCHMARK_TEST_JAR=lib/launchdarkly-java-server-sdk-test.jar
9+
SDK_JARS_DIR=$(PROJECT_DIR)/build/libs
10+
SDK_ALL_JAR=$(SDK_JARS_DIR)/launchdarkly-java-server-sdk-$(SDK_VERSION)-all.jar
11+
SDK_TEST_JAR=$(SDK_JARS_DIR)/launchdarkly-java-server-sdk-$(SDK_VERSION)-test.jar
12+
13+
benchmark: $(BENCHMARK_ALL_JAR) $(BENCHMARK_TEST_JAR)
14+
rm -rf build/tmp
15+
../gradlew jmh
16+
cat build/reports/jmh/human.txt
17+
../gradlew jmhReport
18+
19+
clean:
20+
rm -rf build lib
21+
22+
sdk: $(BENCHMARK_ALL_JAR) $(BENCHMARK_TEST_JAR)
23+
24+
$(BENCHMARK_ALL_JAR): $(SDK_ALL_JAR)
25+
mkdir -p lib
26+
cp $< $@
27+
28+
$(BENCHMARK_TEST_JAR): $(SDK_TEST_JAR)
29+
mkdir -p lib
30+
cp $< $@
31+
32+
$(SDK_ALL_JAR):
33+
cd .. && ./gradlew shadowJarAll
34+
35+
$(SDK_TEST_JAR):
36+
cd .. && ./gradlew testJar

benchmarks/build.gradle

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
buildscript {
3+
repositories {
4+
jcenter()
5+
mavenCentral()
6+
}
7+
}
8+
9+
plugins {
10+
id "me.champeau.gradle.jmh" version "0.5.0"
11+
id "io.morethan.jmhreport" version "0.9.0"
12+
}
13+
14+
repositories {
15+
mavenCentral()
16+
}
17+
18+
ext.versions = [
19+
"jmh": "1.21",
20+
"guava": "19.0"
21+
]
22+
23+
dependencies {
24+
compile files("lib/launchdarkly-java-server-sdk-all.jar")
25+
compile files("lib/launchdarkly-java-server-sdk-test.jar")
26+
compile "com.google.code.gson:gson:2.7"
27+
compile "com.google.guava:guava:${versions.guava}" // required by SDK test code
28+
compile "com.squareup.okhttp3:mockwebserver:3.12.10"
29+
compile "org.openjdk.jmh:jmh-core:1.21"
30+
compile "org.openjdk.jmh:jmh-generator-annprocess:${versions.jmh}"
31+
}
32+
33+
jmh {
34+
iterations = 10 // Number of measurement iterations to do.
35+
benchmarkMode = ['avgt'] // "average time" - reports execution time as ns/op and allocations as B/op.
36+
// batchSize = 1 // Batch size: number of benchmark method calls per operation. (some benchmark modes can ignore this setting)
37+
fork = 1 // How many times to forks a single benchmark. Use 0 to disable forking altogether
38+
// failOnError = false // Should JMH fail immediately if any benchmark had experienced the unrecoverable error?
39+
forceGC = true // Should JMH force GC between iterations?
40+
humanOutputFile = project.file("${project.buildDir}/reports/jmh/human.txt") // human-readable output file
41+
// resultsFile = project.file("${project.buildDir}/reports/jmh/results.txt") // results file
42+
operationsPerInvocation = 3 // Operations per invocation.
43+
// benchmarkParameters = [:] // Benchmark parameters.
44+
profilers = [ 'gc' ] // Use profilers to collect additional data. Supported profilers: [cl, comp, gc, stack, perf, perfnorm, perfasm, xperf, xperfasm, hs_cl, hs_comp, hs_gc, hs_rt, hs_thr]
45+
timeOnIteration = '1s' // Time to spend at each measurement iteration.
46+
resultFormat = 'JSON' // Result format type (one of CSV, JSON, NONE, SCSV, TEXT)
47+
// synchronizeIterations = false // Synchronize iterations?
48+
// threads = 4 // Number of worker threads to run with.
49+
// timeout = '1s' // Timeout for benchmark iteration.
50+
timeUnit = 'ns' // Output time unit. Available time units are: [m, s, ms, us, ns].
51+
verbosity = 'NORMAL' // Verbosity mode. Available modes are: [SILENT, NORMAL, EXTRA]
52+
warmup = '1s' // Time to spend at each warmup iteration.
53+
warmupBatchSize = 2 // Warmup batch size: number of benchmark method calls per operation.
54+
warmupIterations = 1 // Number of warmup iterations to do.
55+
// warmupForks = 0 // How many warmup forks to make for a single benchmark. 0 to disable warmup forks.
56+
// warmupMode = 'INDI' // Warmup mode for warming up selected benchmarks. Warmup modes are: [INDI, BULK, BULK_INDI].
57+
58+
jmhVersion = versions.jmh
59+
}
60+
61+
jmhReport {
62+
jmhResultPath = project.file('build/reports/jmh/results.json')
63+
jmhReportOutput = project.file('build/reports/jmh')
64+
}

benchmarks/settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rootProject.name = 'launchdarkly-java-server-sdk-benchmarks'

0 commit comments

Comments
 (0)