Skip to content

Commit 4361d3d

Browse files
author
Christopher Kolstad
authored
Task/reduce min sdk to21 (#9)
* Removed all java.time usage * fix: Update readme to point out that we've reverted to milliseconds for all durations * Added a couple of more tests of the builders * chore: also add a test that checks that we can configure http client with cache * fix: add readme note about minimum sdk level
1 parent 563d1fb commit 4361d3d

File tree

23 files changed

+225
-101
lines changed

23 files changed

+225
-101
lines changed

README.md

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,8 @@ You will require the SDK on your classpath, so go ahead and add it to your gradl
1111
implementation("io.getunleash:unleash-android-proxy-sdk:${unleash.sdk.version}")
1212
```
1313

14-
### Add support for minSdk < 24
15-
16-
```kotlin
17-
android {
18-
defaultConfig {
19-
// Required when setting minSdkVersion to 20 or lower
20-
multiDexEnabled = true
21-
}
22-
23-
compileOptions {
24-
// Flag to enable support for the new language APIs
25-
coreLibraryDesugaringEnabled = true
26-
// Sets Java compatibility to Java 8
27-
sourceCompatibility = JavaVersion.VERSION_1_8
28-
targetCompatibility = JavaVersion.VERSION_1_8
29-
}
30-
}
31-
dependencies {
32-
// ...
33-
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
34-
35-
// ...
36-
}
37-
```
38-
Reference: https://developer.android.com/studio/write/java8-support
39-
14+
### Minimum Android SDK
15+
- Currently aiming for a minimum SDK level of 21. Keeping in tune with OkHttp's requirement.
4016

4117
### Now configure your client instance
4218

@@ -65,7 +41,7 @@ val context = UnleashContext.newBuilder()
6541
val config = UnleashConfig.newBuilder()
6642
.proxyUrl("URL to your proxy installation")
6743
.clientSecret("yourProxyApiKey")
68-
.pollMode(PollingModes.autoPoll(Duration.ofSeconds(60)) {
44+
.pollMode(PollingModes.autoPoll(60000) { // poll interval in milliseconds
6945
featuresUpdated()
7046
})
7147
.build()
@@ -100,7 +76,7 @@ val context = UnleashContext.newBuilder()
10076
val config = UnleashConfig.newBuilder()
10177
.proxyUrl("URL to your proxy installation")
10278
.clientSecret("yourProxyApiKey")
103-
.pollMode(PollingModes.autoPoll(Duration.ofSeconds(60)) {
79+
.pollMode(PollingModes.autoPoll(60000) { poll interval in milliseconds
10480
featuresUpdated()
10581
})
10682
.build()
@@ -144,6 +120,6 @@ val config = UnleashConfig
144120

145121
The default configuration configures a daemon to report metrics once every minute, this can be altered using the `metricsInterval(Duration d)` method on the builder, so if you'd rather see us post in 5 minutes intervals you could do
146122
```kotlin
147-
UnleasConfig().newBuilder().metricsInterval(Duration.ofMinutes(5))
123+
UnleashConfig().newBuilder().metricsInterval(300000) // Every 5 minutes
148124
```
149125

build.gradle.kts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,22 @@ jacoco {
2626
dependencies {
2727
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
2828
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
29-
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.3")
30-
implementation("com.fasterxml.jackson.core:jackson-core:2.12.3")
31-
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3")
32-
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3")
29+
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.5")
30+
implementation("com.fasterxml.jackson.core:jackson-core:2.12.5")
31+
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.5")
32+
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.5")
3333
implementation("net.sourceforge.streamsupport:android-retrofuture:1.7.3")
3434
api("com.squareup.okhttp3:okhttp:4.9.1")
35-
api("org.slf4j:slf4j-api:1.7.30")
35+
api("org.slf4j:slf4j-api:1.7.32")
3636

3737
testImplementation("org.jetbrains.kotlin:kotlin-test")
3838
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
3939
testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2")
4040
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.7.2")
41-
testImplementation("org.assertj:assertj-core:3.19.0")
41+
testImplementation("org.assertj:assertj-core:3.20.2")
4242
testImplementation("com.squareup.okhttp3:mockwebserver:4.9.1")
4343
testImplementation("org.mockito.kotlin:mockito-kotlin:3.2.0")
44-
testImplementation("org.slf4j:slf4j-simple:1.7.30")
44+
testImplementation("org.slf4j:slf4j-simple:1.7.32")
4545
}
4646

4747
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
@@ -62,9 +62,10 @@ tasks.withType<Test> {
6262
tasks.jacocoTestReport {
6363
dependsOn(tasks.test) // tests are required to run before generating the report
6464
reports {
65-
xml.isEnabled = true
66-
html.isEnabled = true
65+
xml.required.set(true)
66+
html.required.set(true)
6767
}
68+
6869
}
6970

7071

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
4-
distributionSha256Sum=0e46229820205440b48a5501122002842b82886e76af35f0f3a069243dca4b3c
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4+
distributionSha256Sum=f581709a9c35e9cb92e16f585d2c4bc99b2b1a5f85d2badbd3dc6bff59e1e6dd
55
zipStoreBase=GRADLE_USER_HOME
66
zipStorePath=wrapper/dists

samples/android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ android {
1212

1313
defaultConfig {
1414
applicationId "com.example.unleash"
15-
minSdkVersion 26
15+
minSdkVersion 21
1616
targetSdkVersion 30
1717
versionCode 1
1818
versionName "1.0"
@@ -50,7 +50,7 @@ dependencies {
5050
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
5151
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
5252
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
53-
implementation 'io.getunleash:unleash-android-proxy-sdk:0.1.2-SNAPSHOT'
53+
implementation 'io.getunleash:unleash-android-proxy-sdk:0.2.1-SNAPSHOT'
5454
testImplementation 'junit:junit:4.13.2'
5555
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
5656
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

samples/android/app/src/main/java/com/example/unleash/UnleashApplication.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal object UnleashClientModule {
3535
.appName("unleash-android")
3636
.instanceId("unleash-android-${Random.nextLong()}")
3737
.environment("dev")
38-
.clientSecret("proxy-123")
38+
.clientSecret("s1")
3939
.proxyUrl("http://192.168.1.42:3200/proxy")
4040
.enableMetrics()
4141
.pollingMode(

src/main/kotlin/io/getunleash/UnleashClient.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import org.slf4j.Logger
1414
import org.slf4j.LoggerFactory
1515
import java.security.InvalidParameterException
1616
import java9.util.concurrent.CompletableFuture
17+
import java.util.concurrent.TimeUnit
1718
import kotlin.concurrent.timer
1819

1920
/**
@@ -30,8 +31,8 @@ class UnleashClient(
3031
val unleashConfig: UnleashConfig,
3132
var unleashContext: UnleashContext = UnleashContext(),
3233
val httpClient: OkHttpClient = OkHttpClient.Builder()
33-
.readTimeout(unleashConfig.httpClientReadTimeout)
34-
.connectTimeout(unleashConfig.httpClientConnectionTimeout)
34+
.readTimeout(unleashConfig.httpClientReadTimeout, TimeUnit.MILLISECONDS)
35+
.connectTimeout(unleashConfig.httpClientConnectionTimeout, TimeUnit.MILLISECONDS)
3536
.cache(
3637
Cache(
3738
directory = CacheDirectoryProvider().getCacheDirectory(),
@@ -65,8 +66,8 @@ class UnleashClient(
6566
timer(
6667
name = "unleash_report_metrics",
6768
daemon = true,
68-
initialDelay = unleashConfig.reportMetrics.metricsInterval.toMillis(),
69-
period = unleashConfig.reportMetrics.metricsInterval.toMillis()
69+
initialDelay = unleashConfig.reportMetrics.metricsInterval,
70+
period = unleashConfig.reportMetrics.metricsInterval
7071
) {
7172
metricsReporter.reportMetrics()
7273
}
@@ -119,8 +120,8 @@ class UnleashClient(
119120
?: throw IllegalStateException("You must set an UnleashConfig for your UnleashClient"),
120121
unleashContext = this.unleashContext ?: UnleashContext(),
121122
httpClient = this.httpClient ?: OkHttpClient.Builder()
122-
.readTimeout(unleashConfig!!.httpClientReadTimeout)
123-
.connectTimeout(unleashConfig!!.httpClientConnectionTimeout)
123+
.readTimeout(unleashConfig!!.httpClientReadTimeout, TimeUnit.MILLISECONDS)
124+
.connectTimeout(unleashConfig!!.httpClientConnectionTimeout, TimeUnit.MILLISECONDS)
124125
.cache(
125126
Cache(
126127
directory = CacheDirectoryProvider().getCacheDirectory(),

src/main/kotlin/io/getunleash/UnleashConfig.kt

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ package io.getunleash
22

33
import io.getunleash.polling.AutoPollingMode
44
import io.getunleash.polling.PollingMode
5-
import java.time.Duration
65
import java.util.UUID
76

87

9-
data class ReportMetrics(val metricsInterval: Duration = Duration.ofSeconds(60))
8+
data class ReportMetrics(val metricsInterval: Long = 60000)
109
/**
1110
* Represents configuration for Unleash.
1211
* @property url HTTP(s) URL to the Unleash Proxy (Required).
@@ -15,8 +14,8 @@ data class ReportMetrics(val metricsInterval: Duration = Duration.ofSeconds(60))
1514
* @property environment which environment is the application running in. Will be used as default argument for the [io.getunleash.UnleashContext]. (Optional - Defaults to 'default')
1615
* @property instanceId instance id of your client
1716
* @property pollingMode How to poll for features. Defaults to [io.getunleash.polling.AutoPollingMode] with poll interval set to 60 seconds.
18-
* @property httpClientReadTimeout How long to wait for HTTP reads. (Optional - Defaults to 5 seconds)
19-
* @property httpClientConnectionTimeout How long to wait for HTTP connection. (Optional - Defaults to 2 seconds)
17+
* @property httpClientReadTimeout How long to wait for HTTP reads in milliseconds. (Optional - Defaults to 5000)
18+
* @property httpClientConnectionTimeout How long to wait for HTTP connection in milliseconds. (Optional - Defaults to 2000)
2019
* @property httpClientCacheSize Disk space (in bytes) set aside for http cache. (Optional - Defaults to 10MB)
2120
* @property reportMetrics Should the client collate and report metrics? The [io.getunleah.ReportMetrics] dataclass includes a metricsInterval field which defaults to 60 seconds. (Optional - defaults to null)
2221
*/
@@ -26,9 +25,9 @@ data class UnleashConfig(
2625
val appName: String? = null,
2726
val environment: String? = null,
2827
val instanceId: String? = UUID.randomUUID().toString(),
29-
val pollingMode: PollingMode = AutoPollingMode(Duration.ofSeconds(60)),
30-
val httpClientConnectionTimeout: Duration = Duration.ofSeconds(2),
31-
val httpClientReadTimeout: Duration = Duration.ofSeconds(5),
28+
val pollingMode: PollingMode = AutoPollingMode(60000),
29+
val httpClientConnectionTimeout: Long = 2000,
30+
val httpClientReadTimeout: Long = 5000,
3231
val httpClientCacheSize: Long = 1024 * 1024 * 10,
3332
val reportMetrics: ReportMetrics? = null
3433
) {
@@ -66,11 +65,11 @@ data class UnleashConfig(
6665
var appName: String? = null,
6766
var environment: String? = null,
6867
var pollingMode: PollingMode? = null,
69-
var httpClientConnectionTimeout: Duration? = null,
70-
var httpClientReadTimeout: Duration? = null,
68+
var httpClientConnectionTimeout: Long? = null,
69+
var httpClientReadTimeout: Long? = null,
7170
var httpClientCacheSize: Long? = null,
7271
var enableMetrics: Boolean = false,
73-
var metricsInterval: Duration? = null,
72+
var metricsInterval: Long? = null,
7473
var instanceId: String? = null,
7574

7675
) {
@@ -79,27 +78,28 @@ data class UnleashConfig(
7978
fun appName(appName: String) = apply { this.appName = appName }
8079
fun environment(environment: String) = apply { this.environment = environment }
8180
fun pollingMode(pollingMode: PollingMode) = apply { this.pollingMode = pollingMode }
82-
fun httpClientConnectionTimeout(timeout: Duration) = apply { this.httpClientConnectionTimeout = timeout }
83-
fun httpClientConnectionTimeoutInSeconds(seconds: Long) = apply { this.httpClientConnectionTimeout = Duration.ofSeconds(seconds) }
84-
fun httpClientReadTimeout(timeout: Duration) = apply { this.httpClientReadTimeout = timeout }
85-
fun httpClientReadTimeoutInSeconds(seconds: Long) = apply { this.httpClientReadTimeout = Duration.ofSeconds(seconds) }
81+
fun httpClientConnectionTimeout(timeoutInMs: Long) = apply { this.httpClientConnectionTimeout = timeoutInMs }
82+
fun httpClientConnectionTimeoutInSeconds(seconds: Long) = apply { this.httpClientConnectionTimeout = seconds * 1000 }
83+
fun httpClientReadTimeout(timeoutInMs: Long) = apply { this.httpClientReadTimeout = timeoutInMs }
84+
fun httpClientReadTimeoutInSeconds(seconds: Long) = apply { this.httpClientReadTimeout = seconds * 1000 }
8685
fun httpClientCacheSize(cacheSize: Long) = apply { this.httpClientCacheSize = cacheSize }
8786
fun enableMetrics() = apply { this.enableMetrics = true }
8887
fun disableMetrics() = apply { this.enableMetrics = false }
89-
fun metricsInterval(duration: Duration) = apply { this.metricsInterval = duration }
88+
fun metricsInterval(intervalInMs: Long) = apply { this.metricsInterval = intervalInMs }
89+
fun metricsIntervalInSeconds(seconds: Long) = apply { this.metricsInterval = seconds * 1000 }
9090
fun instanceId(id: String) = apply { this.instanceId = id }
9191
fun build(): UnleashConfig = UnleashConfig(
9292
proxyUrl = proxyUrl ?: throw IllegalStateException("You have to set proxy url in your UnleashConfig"),
9393
clientSecret = clientSecret
9494
?: throw IllegalStateException("You have to set client secret in your UnleashConfig"),
9595
appName = appName,
9696
environment = environment,
97-
pollingMode = pollingMode ?: AutoPollingMode(Duration.ofSeconds(60)),
98-
httpClientConnectionTimeout = httpClientConnectionTimeout ?: Duration.ofSeconds(2),
99-
httpClientReadTimeout = httpClientReadTimeout ?: Duration.ofSeconds(5),
100-
httpClientCacheSize = httpClientCacheSize ?: 1024 * 1024 * 10,
97+
pollingMode = pollingMode ?: AutoPollingMode(60000),
98+
httpClientConnectionTimeout = httpClientConnectionTimeout ?: 2000,
99+
httpClientReadTimeout = httpClientReadTimeout ?: 5000,
100+
httpClientCacheSize = httpClientCacheSize ?: (1024 * 1024 * 10),
101101
reportMetrics = if (enableMetrics) {
102-
ReportMetrics(metricsInterval ?: Duration.ofSeconds(60))
102+
ReportMetrics(metricsInterval ?: 60000)
103103
} else {
104104
null
105105
},
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package io.getunleash.data
22

3+
import com.fasterxml.jackson.databind.ObjectMapper
34
import com.fasterxml.jackson.databind.SerializationFeature
5+
import com.fasterxml.jackson.databind.util.StdDateFormat
46
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
57
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
68

79
object Parser {
8-
val jackson = jacksonObjectMapper().registerModule(JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
10+
val jackson: ObjectMapper =
11+
jacksonObjectMapper().registerModule(JavaTimeModule()).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
12+
.setDateFormat(
13+
StdDateFormat().withColonInTimeZone(true)
14+
)
915
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package io.getunleash.errors
22

3-
class ServerException(statusCode: Int) : Exception("Unleash responsded with $statusCode") {
3+
class ServerException(statusCode: Int) : Exception("Unleash responded with $statusCode") {
44
}

src/main/kotlin/io/getunleash/metrics/MetricsReporter.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import org.slf4j.Logger
1616
import org.slf4j.LoggerFactory
1717
import java.io.Closeable
1818
import java.io.IOException
19-
import java.time.Duration
20-
import java.time.Instant
19+
import java.util.Date
20+
import java.util.concurrent.TimeUnit
2121

2222
interface MetricsReporter {
2323
/**
@@ -58,20 +58,20 @@ class NonReporter : MetricsReporter {
5858

5959
data class EvaluationCount(var yes: Int, var no: Int, val variants: MutableMap<String, Int> = mutableMapOf())
6060
data class Bucket(
61-
val start: Instant,
62-
var stop: Instant? = null,
61+
val start: Date,
62+
var stop: Date? = null,
6363
val toggles: MutableMap<String, EvaluationCount> = mutableMapOf()
6464
)
6565

6666
data class Report(val appName: String, val environment: String, val instanceId: String, val bucket: Bucket)
6767

68-
class HttpMetricsReporter(val config: UnleashConfig, val started: Instant = Instant.now()) : MetricsReporter,
68+
class HttpMetricsReporter(val config: UnleashConfig, val started: Date = Date()) : MetricsReporter,
6969
Closeable {
7070
companion object {
7171
val logger: Logger = LoggerFactory.getLogger(MetricsReporter::class.java)
7272
}
7373

74-
val client = OkHttpClient.Builder().callTimeout(Duration.ofSeconds(2)).readTimeout(Duration.ofSeconds(5)).build()
74+
val client = OkHttpClient.Builder().callTimeout(2, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS).build()
7575
val metricsUrl = config.proxyUrl.toHttpUrl().newBuilder().addPathSegment("client").addPathSegment("metrics").build()
7676
private var bucket: Bucket = Bucket(start = started)
7777

@@ -80,7 +80,7 @@ class HttpMetricsReporter(val config: UnleashConfig, val started: Instant = Inst
8080
appName = config.appName ?: "unknown",
8181
instanceId = config.instanceId ?: "not-set",
8282
environment = config.environment ?: "not-set",
83-
bucket = bucket.copy(stop = Instant.now())
83+
bucket = bucket.copy(stop = Date())
8484
)
8585
val request = Request.Builder().url(metricsUrl).post(
8686
Parser.jackson.writeValueAsString(report).toRequestBody("application/json".toMediaType())
@@ -95,7 +95,7 @@ class HttpMetricsReporter(val config: UnleashConfig, val started: Instant = Inst
9595
}
9696
}
9797
})
98-
bucket = Bucket(start = Instant.now())
98+
bucket = Bucket(start = Date())
9999
}
100100

101101
override fun log(featureName: String, enabled: Boolean): Boolean {

0 commit comments

Comments
 (0)