Compare commits

...

124 Commits

Author SHA1 Message Date
renovate[bot] ac3344c7f6
chore(deps): update github/codeql-action digest to 7710ed1 (#1521)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-17 21:51:17 +00:00
renovate[bot] ecc8f7e3ad
chore(deps): update github/codeql-action digest to 03a2a17 (#1520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-17 16:35:35 +02:00
renovate[bot] cbf7a58622
chore(deps): update dependency maven to v3.9.11 (#1519)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-16 06:57:06 +00:00
renovate[bot] 1382b367d9
chore(deps): update actions/setup-java digest to ae2b61d (#1518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-16 03:54:58 +00:00
renovate[bot] 5b3e3656f6
chore(deps): update github/codeql-action digest to 0d17ea4 (#1517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-15 23:46:35 +00:00
renovate[bot] 1d3fab6184
fix(deps): update dependency io.cucumber:cucumber-bom to v7.26.0 (#1516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 16:00:25 +02:00
renovate[bot] 006ae75e2b
chore(deps): update github/codeql-action digest to 6f936b5 (#1515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 15:49:08 +02:00
renovate[bot] aa0569379b
chore(deps): update github/codeql-action digest to f53ec7c (#1512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-11 01:45:44 +00:00
renovate[bot] bf68cbdedf
fix(deps): update dependency io.cucumber:cucumber-bom to v7.25.0 (#1514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-10 20:57:58 +00:00
renovate[bot] 62738f7f16
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v2.45.0 (#1509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 10:17:05 +02:00
renovate[bot] 1e8f5c880c
chore(deps): update dependency com.google.guava:guava to v33.4.8-jre (#1382)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 06:34:38 +00:00
renovate[bot] 488196656a
fix(deps): update dependency io.cucumber:cucumber-bom to v7.24.0 (#1510)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 08:28:26 +02:00
renovate[bot] 26716a51cf
chore(deps): update github/codeql-action digest to 624d0bc (#1507)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 03:14:51 +00:00
renovate[bot] 908755c2c2
chore(deps): update actions/setup-java digest to c190c18 (#1508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-07 23:04:40 +00:00
OpenFeature Bot d2b1dc3a41
chore(main): release 1.16.0 (#1452)
Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com>
2025-07-07 14:54:59 -04:00
Todd Baert 85d89ee79a chore: update publish env vars
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-07-07 14:42:51 -04:00
Todd Baert 6194186b3e chore: skip tests on publish
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-07-07 14:39:17 -04:00
Todd Baert 5425a34a12 chore: migrate to new publish
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-07-07 14:30:18 -04:00
renovate[bot] 957c0d1ba3
fix(deps): update dependency org.junit:junit-bom to v5.13.3 (#1505)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-04 19:37:31 +00:00
chrfwow ebea0fdf1c
fix: Reduce locking and concurrency issues (#1478)
* Reduce locking and concurrency issues

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* Reduce locking and concurrency issues

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* formatting

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* use concurrent data structure for hooks

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* use concurrent data structure for hooks

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

---------

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>
Co-authored-by: Todd Baert <todd.baert@dynatrace.com>
2025-07-04 09:17:56 -04:00
renovate[bot] 08f549afd1
chore(deps): update actions/setup-java digest to 67aec00 (#1504)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-03 23:29:05 +00:00
renovate[bot] a5d1cbced4
chore(deps): update github/codeql-action digest to b694213 (#1503)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-03 19:13:17 +00:00
renovate[bot] 0fd9d3dcfb
chore(deps): update github/codeql-action digest to 33f8489 (#1502)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-03 00:11:36 +00:00
renovate[bot] 0515ad54c4
chore(deps): update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.8 (#1501)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-02 13:05:20 +02:00
renovate[bot] 69519b1ef7
chore(deps): update github/codeql-action digest to dcc1a66 (#1499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 20:37:12 +00:00
renovate[bot] 2e3b479cb1
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10.26.1 (#1498)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 01:58:05 +00:00
renovate[bot] 49214b7282
chore(deps): update github/codeql-action digest to 4c57370 (#1497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-27 23:59:31 +00:00
renovate[bot] fc430c3e1d
chore(deps): update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.3.2 (#1496)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-27 07:35:50 +02:00
renovate[bot] 86a5916f0d
chore(deps): update github/codeql-action digest to 8ef1782 (#1495)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-26 14:54:48 +02:00
renovate[bot] 34b22e8d93
fix(deps): update dependency org.junit:junit-bom to v5.13.2 (#1492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 06:40:04 +00:00
renovate[bot] 300a705e0a
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10.26.0 (#1494)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 08:32:52 +02:00
renovate[bot] b64efe82d9
chore(deps): update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.3.1 (#1493)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-25 02:49:37 +00:00
renovate[bot] 6f67b06f71
chore(deps): update github/codeql-action digest to 9b02dc2 (#1491)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 20:50:48 +00:00
renovate[bot] e67f598357
chore(deps): update actions/setup-java digest to ebb356c (#1490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-23 22:42:58 +00:00
renovate[bot] 312b6df5d2
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10.25.1 (#1489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-21 21:10:50 +00:00
renovate[bot] 8fad544b17
chore(deps): update github/codeql-action digest to ac30a39 (#1488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 19:08:37 +00:00
renovate[bot] c3eaecdb8b
chore(deps): update github/codeql-action digest to 66d7255 (#1487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-20 01:25:24 +00:00
renovate[bot] 7c2af57a36
chore(deps): update actions/cache digest to 640a1c2 (#1485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 20:05:59 +00:00
renovate[bot] 8bf777a7e9
chore(deps): update github/codeql-action digest to ef36b69 (#1484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 04:48:36 +00:00
renovate[bot] 936ff60fac
chore(deps): update dependency net.bytebuddy:byte-buddy-agent to v1.17.6 (#1483)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 16:50:34 +00:00
renovate[bot] 99a3006de8
chore(deps): update github/codeql-action digest to 3de706a (#1481)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 16:44:00 +00:00
renovate[bot] 8e51e6fe10
chore(deps): update dependency net.bytebuddy:byte-buddy to v1.17.6 (#1482)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 18:37:11 +02:00
renovate[bot] 844d5e244b
chore(deps): update github/codeql-action digest to be30325 (#1479)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-13 18:52:24 +00:00
renovate[bot] 0b57bcafc1
chore(deps): update github/codeql-action digest to 466d6ce (#1477)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-11 21:43:28 +00:00
chrfwow 3dd7d5d426
feat: add means of awaiting event emission, fix flaky build (#1463)
## This PR

- adds the ability to await event emissions by returning a new construct
- uses this construct in tests

⚠️ in rare cases, this could be a breaking change, but the events API is currently experimental, so we will not do a major version ubmp

### Related Issues

Fixes #1449
2025-06-10 11:27:15 -04:00
renovate[bot] 6cca721be5
chore(deps): update github/codeql-action digest to 7cb9b16 (#1476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 01:27:44 +00:00
renovate[bot] 4481537ceb
chore(deps): update dependency maven to v3.9.10 (#1474)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-07 21:59:01 +00:00
renovate[bot] b5d873e44d
chore(deps): update actions/checkout digest to 09d2aca (#1473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-07 17:39:13 +00:00
renovate[bot] 545d6aac09
fix(deps): update dependency org.junit:junit-bom to v5.13.1 (#1475)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-07 13:08:10 +00:00
renovate[bot] 2dcd6a1dd0
chore(deps): update github/codeql-action digest to b1e4dc3 (#1471)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-05 06:27:45 +00:00
Simon Schrottner 3ed65cfb0c
chore: remove unneeded version information (#1428)
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-06-04 14:44:38 +00:00
renovate[bot] 6597de7a98
chore(deps): update github/codeql-action digest to 075e08a (#1470)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-03 18:05:22 +00:00
renovate[bot] 376f81f5c3
chore(deps): update github/codeql-action digest to 4a00331 (#1469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 19:28:18 +00:00
renovate[bot] 1558a86249
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10.25.0 (#1468)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-31 21:27:57 +00:00
renovate[bot] f8260a1c3a
fix(deps): update junit5 monorepo (#1467)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 21:02:38 +00:00
renovate[bot] 50a6b168a7
fix(deps): update dependency io.cucumber:cucumber-bom to v7.23.0 (#1466)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 05:38:25 +00:00
renovate[bot] b6ceff2ecb
chore(deps): update dependency org.codehaus.mojo:exec-maven-plugin to v3.5.1 (#1461)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-30 02:01:25 +00:00
renovate[bot] 2de7616676
chore(deps): update io.cucumber.version to v7.23.0 (#1465)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-29 23:00:03 +00:00
renovate[bot] f10aaaa357
chore(deps): update github/codeql-action digest to 7fd6215 (#1464)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 22:25:40 +00:00
renovate[bot] 40b319c5de
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v2.44.5 (#1462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-28 04:12:52 +00:00
renovate[bot] 5e922cf3ef
chore(deps): update github/codeql-action digest to bc02a25 (#1460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-27 22:26:25 +00:00
renovate[bot] 6a95c008e9
chore(deps): update github/codeql-action digest to 7b0fb5a (#1459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-22 22:59:22 +00:00
renovate[bot] dcbfd265a3
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10.24.0 (#1458)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-22 06:29:34 +00:00
renovate[bot] e17b0b2975
chore(deps): update dependency org.mockito:mockito-core to v5.18.0 (#1457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-21 04:08:45 +00:00
renovate[bot] b45a937017
chore(deps): update github/codeql-action digest to 396fd27 (#1456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 23:54:03 +00:00
renovate[bot] 36eed065e7
chore(deps): update github/codeql-action digest to 57eebf6 (#1455)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-16 15:06:06 +00:00
renovate[bot] e3379395e6
chore(deps): update codecov/codecov-action action to v5.4.3 (#1454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-16 01:40:23 +00:00
renovate[bot] b667aa3251
chore(deps): update github/codeql-action digest to b86edfc (#1453)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-15 20:01:17 +00:00
Todd Baert 1714efe81a
chore: improvements to release workflow (#1451)
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Co-authored-by: chrfwow <christian.lutnik@dynatrace.com>
2025-05-15 11:22:10 -04:00
renovate[bot] d9a72d2aaf
chore(deps): update github/codeql-action digest to 510dfa3 (#1450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-14 22:43:05 +00:00
OpenFeature Bot cfd9512728
chore(main): release 1.15.1 (#1448)
* chore(main): release 1.15.1

Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com>

* fixup: change version

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

---------

Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-05-14 14:12:11 +02:00
Todd Baert f6bd30db93
chore: update boostrap sha for release please
Creating a new build

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-05-14 07:57:13 -04:00
chrfwow e2813b2e5d
feat: add logging on provider state transitions (#1444)
* NOISSUE add logging on provider state transitions

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* fix npe

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* fix failing test

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* fix failing test

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

* format

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

---------

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>
Co-authored-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-05-14 11:11:36 +02:00
renovate[bot] bc10bacb5a
chore(deps): update github/codeql-action digest to 15bce5b (#1443)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-13 22:40:47 +00:00
OpenFeature Bot 7182a7fc41
chore(main): release 1.15.0 (#1431)
Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com>
2025-05-13 12:38:55 -04:00
Liran M d0ae548277
feat: add telemetry helper utils (#1346)
* feat: add telemetry helper utils

Signed-off-by: liran2000 <liran2000@gmail.com>

* updates

Signed-off-by: liran2000 <liran2000@gmail.com>

* fixup: apply changes according to the semconv

The semconv has changed, and some attributes have been
renamed. Furthermore, the body usage is deprecated
and should be part of the attributes.

see: https://github.com/open-telemetry/semantic-conventions/pull/1990/
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* fixup: fix tests

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* fixup: fix spotless

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

---------

Signed-off-by: liran2000 <liran2000@gmail.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-05-13 09:45:16 +02:00
renovate[bot] e568f3a4f5
fix(deps): update dependency io.cucumber:cucumber-bom to v7.22.2 (#1442)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 07:07:53 +00:00
renovate[bot] 58454b4eaa
chore(deps): update io.cucumber.version to v7.22.2 (#1441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 09:01:29 +02:00
renovate[bot] 78657ee79e
chore(deps): update dependency com.tngtech.archunit:archunit-junit5 to v1.4.1 (#1440)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-08 03:06:04 +00:00
renovate[bot] 3403510515
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10 (#103)
* chore(deps): update dependency com.puppycrawl.tools:checkstyle to v10

* Fix javadoc format

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>

---------

Signed-off-by: christian.lutnik <christian.lutnik@dynatrace.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: christian.lutnik <christian.lutnik@dynatrace.com>
Co-authored-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-05-06 06:19:41 +00:00
jarebudev 4dc988b637
feat!: Raise required Java version to 11 (#1393)
* bumped to java 11, altered CI to target java 11

Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com>

* changed profile and toolchain

Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com>

* corrected toolchain version

Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com>

---------

Signed-off-by: jarebudev <23311805+jarebudev@users.noreply.github.com>
Co-authored-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-05-05 09:30:23 +00:00
renovate[bot] f2348ea370
chore(deps): update github/codeql-action digest to 5eb3ed6 (#1439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-02 18:13:36 +00:00
renovate[bot] 85b200a08b
chore(deps): update github/codeql-action digest to 97a2bfd (#1438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-01 18:38:45 +00:00
renovate[bot] f965cbcb37
chore(deps): update github/codeql-action digest to 40e16ed (#1437)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-30 23:46:35 +00:00
renovate[bot] b09e88798f
chore(deps): update github/codeql-action digest to ed51cb5 (#1436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 19:28:15 +00:00
renovate[bot] 7e74f2aa3a
chore(deps): update github/codeql-action digest to 83605b3 (#1435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-29 02:56:28 +00:00
renovate[bot] 62ba6db457
chore(deps): update amannn/action-semantic-pull-request digest to 3352882 (#1434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 20:32:23 +00:00
Abhay Porwal 96cf9c7f54
docs: add try-catch example for setProviderAndWait usage (#1433)
* added the detailed instructions for the setProviderAndWait

Signed-off-by: Abhay <abhayakg123@gmail.com.com>

* fixup: checkstyle issues

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

---------

Signed-off-by: Abhay <abhayakg123@gmail.com.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Abhay <abhayakg123@gmail.com.com>
Co-authored-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-04-28 14:34:19 +02:00
renovate[bot] 99faaf88aa
chore(deps): update github/codeql-action digest to f843d94 (#1432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-25 22:07:09 +00:00
Todd Baert 1cc851b293
chore: update release please action (#1430)
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-04-24 21:41:37 -04:00
Todd Baert 32137bfa82
chore: add DCO to release please (#1429)
* chore: add DCO to release please

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>

* Update release-please-config.json

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>

---------

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-04-24 21:14:07 -04:00
Todd Baert 45ec4b1b77
chore: add DCO to release please
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-04-24 20:58:47 -04:00
Todd Baert 014f8a59da
chore: use PAT for release please
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-04-24 19:32:45 -04:00
renovate[bot] 1c4d2efafd
fix(deps): update dependency io.cucumber:cucumber-bom to v7.22.1 (#1427)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 18:19:32 +00:00
renovate[bot] 844374a42b
chore(deps): update io.cucumber.version to v7.22.1 (#1426)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 15:19:34 +00:00
renovate[bot] a7828e73a8
chore(deps): update github/codeql-action digest to 4ffa236 (#1425)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-23 22:47:18 +00:00
renovate[bot] 6b6849f3a3
chore(deps): update github/codeql-action digest to 2a8cbad (#1423)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-22 19:25:23 +00:00
renovate[bot] 495da271be
chore(deps): update dependency com.h3xstream.findsecbugs:findsecbugs-plugin to v1.14.0 (#1422)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-20 10:02:26 +00:00
renovate[bot] e19ccaa35d
chore(deps): update dependency org.jacoco:jacoco-maven-plugin to v0.8.13 (#1407)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-18 08:15:55 +02:00
Simon Schrottner 498fd38265
chore: update codeowners to give global maintainers code ownership (#1412)
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
2025-04-17 11:33:57 -04:00
renovate[bot] a3e2a59aeb
chore(deps): update actions/setup-java digest to f4f1212 (#1421)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-16 21:41:52 +00:00
Todd Baert 665dd51eb2
chore: add publish env (#1420)
* chore: add publish env

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>

* Update release.yml

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>

* Update merge.yml

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>

---------

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
2025-04-16 12:45:16 -04:00
renovate[bot] a6389e89f6
chore(deps): update codecov/codecov-action action to v5.4.2 (#1419)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 03:44:53 +00:00
renovate[bot] 97b442ed6e
fix(deps): update junit5 monorepo (#1418)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 21:45:27 +00:00
renovate[bot] 0c77c84460
chore(deps): update github/codeql-action digest to 4c3e536 (#1417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 02:21:54 +00:00
renovate[bot] 4607c62f15
chore(deps): update github/codeql-action digest to 56dd02f (#1416)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-09 22:09:23 +00:00
renovate[bot] a5789038ac
chore(deps): update actions/setup-java digest to c5195ef (#1415)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 23:02:50 +00:00
renovate[bot] e066d3f749
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v2.44.4 (#1414)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 06:34:39 +00:00
renovate[bot] 5b327eeb77
chore(deps): update github/codeql-action digest to d26c46a (#1413)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 01:31:00 +00:00
renovate[bot] e25181982a
fix(deps): update dependency io.cucumber:cucumber-bom to v7.22.0 (#1411)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-05 10:23:07 +00:00
renovate[bot] 3c69f2f36c
chore(deps): update io.cucumber.version to v7.22.0 (#1410)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-05 06:25:16 +00:00
renovate[bot] 345cdcfa10
chore(deps): update dependency org.mockito:mockito-core to v5.17.0 (#1409)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-04 18:42:05 +00:00
renovate[bot] ca160cab7c
chore(deps): update github/codeql-action digest to 362ef4c (#1408)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-03 18:12:31 +00:00
renovate[bot] e211397d51
chore(deps): update github/codeql-action digest to e13fe0d (#1406)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-03 02:18:17 +00:00
renovate[bot] 5b2f1513ab
chore(deps): update github/codeql-action digest to dab8a02 (#1405)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-02 17:47:53 +00:00
renovate[bot] f834e11acc
chore(deps): update actions/setup-java digest to 148017a (#1404)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 22:21:36 +00:00
renovate[bot] ef32f11571
fix(deps): update dependency org.projectlombok:lombok to v1.18.38 (#1403)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-01 03:02:58 +00:00
renovate[bot] 07301bda3f
chore(deps): update dependency net.bytebuddy:byte-buddy-agent to v1.17.5 (#1401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 23:11:43 +00:00
renovate[bot] 384953d30e
chore(deps): update github/codeql-action digest to efffb48 (#1402)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 18:29:21 +00:00
renovate[bot] 1f2d071508
chore(deps): update dependency net.bytebuddy:byte-buddy to v1.17.5 (#1400)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 15:00:52 +00:00
renovate[bot] d6ebc161a9
chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.3 (#1399)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 10:47:07 +00:00
renovate[bot] 1fcf0e77d9
chore(deps): update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.5.3 (#1398)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 05:38:29 +00:00
renovate[bot] 37d76be697
chore(deps): update github/codeql-action digest to 9f45e74 (#1396)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-28 23:26:09 +00:00
renovate[bot] d7b591c9f9
chore(deps): update github/codeql-action digest to 9bd18b4 (#1394)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-27 23:40:23 +00:00
33 changed files with 910 additions and 289 deletions

View File

@ -18,6 +18,6 @@ jobs:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@04501d43b574e4c1d23c629ffe4dcec27acfdeff
- uses: amannn/action-semantic-pull-request@335288255954904a41ddda8947c8f2c844b8bfeb
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -9,29 +9,31 @@ name: on-merge
on:
push:
branches: [ master, main ]
branches:
- main
permissions:
contents: read
jobs:
build:
environment: publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
- uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
- name: Set up JDK 17
uses: actions/setup-java@3b6c050358614dd082e53cdbc55580431fc4e437
uses: actions/setup-java@ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597
with:
java-version: '17'
distribution: 'temurin'
cache: maven
server-id: ossrh
server-username: ${{ secrets.OSSRH_USERNAME }}
server-password: ${{ secrets.OSSRH_PASSWORD }}
server-id: central
server-username: ${{ secrets.CENTRAL_USERNAME }}
server-password: ${{ secrets.CENTRAL_PASSWORD }}
- name: Cache local Maven repository
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684
uses: actions/cache@640a1c2554105b57832a23eea0b4672fc7a790d5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-17-maven-${{ hashFiles('**/pom.xml') }}
@ -48,7 +50,7 @@ jobs:
run: mvn --batch-mode --update-snapshots verify
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5.4.0
uses: codecov/codecov-action@v5.4.3
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
flags: unittests # optional
@ -63,7 +65,7 @@ jobs:
- name: Deploy
run: |
mvn --batch-mode \
--settings release/m2-settings.xml clean deploy
--settings release/m2-settings.xml -DskipTests clean deploy
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}

View File

@ -13,28 +13,28 @@ jobs:
build:
- java: 17
profile: codequality
- java: 8
profile: java8
- java: 11
profile: java11
name: with Java ${{ matrix.build.java }}
runs-on: ${{ matrix.os}}
steps:
- name: Check out the code
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
- name: Set up JDK 8
uses: actions/setup-java@3b6c050358614dd082e53cdbc55580431fc4e437
- name: Set up JDK 11
uses: actions/setup-java@ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597
with:
java-version: ${{ matrix.build.java }}
distribution: 'temurin'
cache: maven
- name: Initialize CodeQL
uses: github/codeql-action/init@486ab5a2922b634015408a83e10f6867efb5922c
uses: github/codeql-action/init@7710ed11e398ea99c7f7004c2b2e0f580458db42
with:
languages: java
- name: Cache local Maven repository
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684
uses: actions/cache@640a1c2554105b57832a23eea0b4672fc7a790d5
with:
path: ~/.m2/repository
key: ${{ runner.os }}${{ matrix.build.java }}-maven-${{ hashFiles('**/pom.xml') }}
@ -46,7 +46,7 @@ jobs:
- if: matrix.build.java == '17'
name: Upload coverage to Codecov
uses: codecov/codecov-action@v5.4.0
uses: codecov/codecov-action@v5.4.3
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
flags: unittests # optional
@ -55,4 +55,4 @@ jobs:
verbose: true # optional (default = false)
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@486ab5a2922b634015408a83e10f6867efb5922c
uses: github/codeql-action/analyze@7710ed11e398ea99c7f7004c2b2e0f580458db42

View File

@ -12,46 +12,53 @@ permissions: # added using https://github.com/step-security/secure-workflows
jobs:
release-please:
permissions:
contents: write # for google-github-actions/release-please-action to create release commit
pull-requests: write # for google-github-actions/release-please-action to create release PR
runs-on: ubuntu-latest
permissions:
contents: write # for googleapis/release-please-action to create release commit
pull-requests: write # for googleapis/release-please-action to create release PR
issues: write # for googleapis/release-please-action to create labels
# Release-please creates a PR that tracks all changes
steps:
- uses: google-github-actions/release-please-action@e4dc86ba9405554aeba3c6bb2d169500e7d3b4ee
- uses: googleapis/release-please-action@v4
id: release
with:
token: ${{secrets.GITHUB_TOKEN}}
target-branch: main
token: ${{secrets.RELEASE_PLEASE_ACTION_TOKEN}}
outputs:
release_created: ${{ fromJSON(steps.release.outputs.paths_released)[0] != null }} # if we have a single release path, do the release
publish:
environment: publish
runs-on: ubuntu-latest
permissions:
contents: read
needs: release-please
if: ${{ fromJSON(needs.release-please.outputs.release_created || false) }}
steps:
- name: Checkout Repository
uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
# These steps are only run if this was a merged release-please PR
- name: checkout
if: ${{ steps.release.outputs.release_created }}
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
- name: Set up JDK 17
if: ${{ steps.release.outputs.release_created }}
uses: actions/setup-java@3b6c050358614dd082e53cdbc55580431fc4e437
uses: actions/setup-java@ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597
with:
java-version: '17'
distribution: 'temurin'
cache: maven
server-id: ossrh
server-username: ${{ secrets.OSSRH_USERNAME }}
server-password: ${{ secrets.OSSRH_PASSWORD }}
server-id: central
server-username: ${{ secrets.CENTRAL_USERNAME }}
server-password: ${{ secrets.CENTRAL_PASSWORD }}
- name: Configure GPG Key
if: ${{ steps.release.outputs.release_created }}
run: |
echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
env:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
- name: Deploy
if: ${{ steps.release.outputs.release_created }}
run: |
mvn --batch-mode \
--settings release/m2-settings.xml clean deploy
--settings release/m2-settings.xml -DskipTests clean deploy
env:
OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}

View File

@ -29,16 +29,16 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@85e6279cec87321a52edac9c87bce653a07cf6c2
uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@486ab5a2922b634015408a83e10f6867efb5922c
uses: github/codeql-action/init@7710ed11e398ea99c7f7004c2b2e0f580458db42
with:
languages: java
- name: Autobuild
uses: github/codeql-action/autobuild@486ab5a2922b634015408a83e10f6867efb5922c
uses: github/codeql-action/autobuild@7710ed11e398ea99c7f7004c2b2e0f580458db42
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@486ab5a2922b634015408a83e10f6867efb5922c
uses: github/codeql-action/analyze@7710ed11e398ea99c7f7004c2b2e0f580458db42

View File

@ -16,4 +16,4 @@
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip

View File

@ -1 +1 @@
{".":"1.14.2"}
{".":"1.16.0"}

View File

@ -1,5 +1,148 @@
# Changelog
## [1.16.0](https://github.com/open-feature/java-sdk/compare/v1.15.1...v1.16.0) (2025-07-07)
### 🐛 Bug Fixes
* **deps:** update dependency io.cucumber:cucumber-bom to v7.23.0 ([#1466](https://github.com/open-feature/java-sdk/issues/1466)) ([50a6b16](https://github.com/open-feature/java-sdk/commit/50a6b168a7de40337aa51ef3d79d122030956cb9))
* **deps:** update dependency org.junit:junit-bom to v5.13.1 ([#1475](https://github.com/open-feature/java-sdk/issues/1475)) ([545d6aa](https://github.com/open-feature/java-sdk/commit/545d6aac09dbc74c00a0a4e5c26f4ef80be22379))
* **deps:** update dependency org.junit:junit-bom to v5.13.2 ([#1492](https://github.com/open-feature/java-sdk/issues/1492)) ([34b22e8](https://github.com/open-feature/java-sdk/commit/34b22e8d93a986fdb81500ab539b4d2fe038b618))
* **deps:** update dependency org.junit:junit-bom to v5.13.3 ([#1505](https://github.com/open-feature/java-sdk/issues/1505)) ([957c0d1](https://github.com/open-feature/java-sdk/commit/957c0d1ba38ecc758c1ec164e40070ac93a01d68))
* **deps:** update junit5 monorepo ([#1467](https://github.com/open-feature/java-sdk/issues/1467)) ([f8260a1](https://github.com/open-feature/java-sdk/commit/f8260a1c3a345c877eba95bfe41184ad11f6555e))
* Reduce locking and concurrency issues ([#1478](https://github.com/open-feature/java-sdk/issues/1478)) ([ebea0fd](https://github.com/open-feature/java-sdk/commit/ebea0fdf1cf3e6f4d2e8aebf2dcb7c7e1f31acc2))
### ✨ New Features
* add means of awaiting event emission, fix flaky build ([#1463](https://github.com/open-feature/java-sdk/issues/1463)) ([3dd7d5d](https://github.com/open-feature/java-sdk/commit/3dd7d5d4262f1f4461e13c13a7d64d2fa8bfd764)), closes [#1449](https://github.com/open-feature/java-sdk/issues/1449)
### 🧹 Chore
* **deps:** update actions/cache digest to 640a1c2 ([#1485](https://github.com/open-feature/java-sdk/issues/1485)) ([7c2af57](https://github.com/open-feature/java-sdk/commit/7c2af57a362ee11f757a431ee17eff3ee448bf6c))
* **deps:** update actions/checkout digest to 09d2aca ([#1473](https://github.com/open-feature/java-sdk/issues/1473)) ([b5d873e](https://github.com/open-feature/java-sdk/commit/b5d873e44d3c41b42f11569b0fafccc0a002ebdd))
* **deps:** update actions/setup-java digest to 67aec00 ([#1504](https://github.com/open-feature/java-sdk/issues/1504)) ([08f549a](https://github.com/open-feature/java-sdk/commit/08f549afd1fd26581b2a8e063832ec986c5e3267))
* **deps:** update actions/setup-java digest to ebb356c ([#1490](https://github.com/open-feature/java-sdk/issues/1490)) ([e67f598](https://github.com/open-feature/java-sdk/commit/e67f5983573afff805a56ef18584d1a7291ccafc))
* **deps:** update codecov/codecov-action action to v5.4.3 ([#1454](https://github.com/open-feature/java-sdk/issues/1454)) ([e337939](https://github.com/open-feature/java-sdk/commit/e3379395e6bfb0ce811d8372761a3cb015ad2cde))
* **deps:** update dependency com.diffplug.spotless:spotless-maven-plugin to v2.44.5 ([#1462](https://github.com/open-feature/java-sdk/issues/1462)) ([40b319c](https://github.com/open-feature/java-sdk/commit/40b319c5de0461bec13f76978ae09edc958310cd))
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.3.1 ([#1493](https://github.com/open-feature/java-sdk/issues/1493)) ([b64efe8](https://github.com/open-feature/java-sdk/commit/b64efe82d993defe070dfeb9aa60e740ccf757cd))
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.3.2 ([#1496](https://github.com/open-feature/java-sdk/issues/1496)) ([fc430c3](https://github.com/open-feature/java-sdk/commit/fc430c3e1d57a532d8c0c879c3e7e25c46d4ad84))
* **deps:** update dependency com.puppycrawl.tools:checkstyle to v10.24.0 ([#1458](https://github.com/open-feature/java-sdk/issues/1458)) ([dcbfd26](https://github.com/open-feature/java-sdk/commit/dcbfd265a3875271695af760fce9870e53c69f13))
* **deps:** update dependency com.puppycrawl.tools:checkstyle to v10.25.0 ([#1468](https://github.com/open-feature/java-sdk/issues/1468)) ([1558a86](https://github.com/open-feature/java-sdk/commit/1558a862497c0e133d11d53ff6d7f28437653d43))
* **deps:** update dependency com.puppycrawl.tools:checkstyle to v10.25.1 ([#1489](https://github.com/open-feature/java-sdk/issues/1489)) ([312b6df](https://github.com/open-feature/java-sdk/commit/312b6df5d2c891ac758bf398f8399ecd25b7597e))
* **deps:** update dependency com.puppycrawl.tools:checkstyle to v10.26.0 ([#1494](https://github.com/open-feature/java-sdk/issues/1494)) ([300a705](https://github.com/open-feature/java-sdk/commit/300a705e0af959da7ed0e88e9975379ff6fc4138))
* **deps:** update dependency com.puppycrawl.tools:checkstyle to v10.26.1 ([#1498](https://github.com/open-feature/java-sdk/issues/1498)) ([2e3b479](https://github.com/open-feature/java-sdk/commit/2e3b479cb1e8b0b65652ee813eaa2e1940d53c8e))
* **deps:** update dependency maven to v3.9.10 ([#1474](https://github.com/open-feature/java-sdk/issues/1474)) ([4481537](https://github.com/open-feature/java-sdk/commit/4481537cebc213dcfe19bb8cd9b70a4c91a682b2))
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.6 ([#1482](https://github.com/open-feature/java-sdk/issues/1482)) ([8e51e6f](https://github.com/open-feature/java-sdk/commit/8e51e6fe101882184a5d09be31fa65563d82c673))
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.6 ([#1483](https://github.com/open-feature/java-sdk/issues/1483)) ([936ff60](https://github.com/open-feature/java-sdk/commit/936ff60fac471a83a7c14412d2e825b2a7f9704c))
* **deps:** update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.8 ([#1501](https://github.com/open-feature/java-sdk/issues/1501)) ([0515ad5](https://github.com/open-feature/java-sdk/commit/0515ad54c4f71863373eb1b7f429393923b27d90))
* **deps:** update dependency org.codehaus.mojo:exec-maven-plugin to v3.5.1 ([#1461](https://github.com/open-feature/java-sdk/issues/1461)) ([b6ceff2](https://github.com/open-feature/java-sdk/commit/b6ceff2ecb0e34be2ccdb83f7f37c1177de6f27e))
* **deps:** update dependency org.mockito:mockito-core to v5.18.0 ([#1457](https://github.com/open-feature/java-sdk/issues/1457)) ([e17b0b2](https://github.com/open-feature/java-sdk/commit/e17b0b29758ae7cdbdac9ddb2178382c55eb1277))
* **deps:** update github/codeql-action digest to 075e08a ([#1470](https://github.com/open-feature/java-sdk/issues/1470)) ([6597de7](https://github.com/open-feature/java-sdk/commit/6597de7a98e0fae10a541a8a9b60837623c133a8))
* **deps:** update github/codeql-action digest to 33f8489 ([#1502](https://github.com/open-feature/java-sdk/issues/1502)) ([0fd9d3d](https://github.com/open-feature/java-sdk/commit/0fd9d3dcfb1fd65197a42885b12d40a1cc152d3b))
* **deps:** update github/codeql-action digest to 396fd27 ([#1456](https://github.com/open-feature/java-sdk/issues/1456)) ([b45a937](https://github.com/open-feature/java-sdk/commit/b45a9370173e3d3b97c78449dfc99225fb572228))
* **deps:** update github/codeql-action digest to 3de706a ([#1481](https://github.com/open-feature/java-sdk/issues/1481)) ([99a3006](https://github.com/open-feature/java-sdk/commit/99a3006de878ab0ba1f0e61a4cb5432914425795))
* **deps:** update github/codeql-action digest to 466d6ce ([#1477](https://github.com/open-feature/java-sdk/issues/1477)) ([0b57bca](https://github.com/open-feature/java-sdk/commit/0b57bcafc14b946000feb4a3421d73b9616e83cb))
* **deps:** update github/codeql-action digest to 4a00331 ([#1469](https://github.com/open-feature/java-sdk/issues/1469)) ([376f81f](https://github.com/open-feature/java-sdk/commit/376f81f5c3b66d7e3e298aac30ac7544b84e7362))
* **deps:** update github/codeql-action digest to 4c57370 ([#1497](https://github.com/open-feature/java-sdk/issues/1497)) ([49214b7](https://github.com/open-feature/java-sdk/commit/49214b7282ddde1ee16cf80f92c11cc90ef7612a))
* **deps:** update github/codeql-action digest to 510dfa3 ([#1450](https://github.com/open-feature/java-sdk/issues/1450)) ([d9a72d2](https://github.com/open-feature/java-sdk/commit/d9a72d2aafd787a1814132f000897ad1c94181e4))
* **deps:** update github/codeql-action digest to 57eebf6 ([#1455](https://github.com/open-feature/java-sdk/issues/1455)) ([36eed06](https://github.com/open-feature/java-sdk/commit/36eed065e763bbfa0f8f97d704202bbd219332ca))
* **deps:** update github/codeql-action digest to 66d7255 ([#1487](https://github.com/open-feature/java-sdk/issues/1487)) ([c3eaecd](https://github.com/open-feature/java-sdk/commit/c3eaecdb8b34d3b33946bd205ee92d49584602bd))
* **deps:** update github/codeql-action digest to 7b0fb5a ([#1459](https://github.com/open-feature/java-sdk/issues/1459)) ([6a95c00](https://github.com/open-feature/java-sdk/commit/6a95c008e975dd3c7328c32f1d7cf626bbaecfa6))
* **deps:** update github/codeql-action digest to 7cb9b16 ([#1476](https://github.com/open-feature/java-sdk/issues/1476)) ([6cca721](https://github.com/open-feature/java-sdk/commit/6cca721be5bc6f5926fe64668a7c03728cab3cb0))
* **deps:** update github/codeql-action digest to 7fd6215 ([#1464](https://github.com/open-feature/java-sdk/issues/1464)) ([f10aaaa](https://github.com/open-feature/java-sdk/commit/f10aaaa357581b573895f4d6e2329abb705582aa))
* **deps:** update github/codeql-action digest to 8ef1782 ([#1495](https://github.com/open-feature/java-sdk/issues/1495)) ([86a5916](https://github.com/open-feature/java-sdk/commit/86a5916f0dc6116b5b9e5dc897ff4b8705ac01e3))
* **deps:** update github/codeql-action digest to 9b02dc2 ([#1491](https://github.com/open-feature/java-sdk/issues/1491)) ([6f67b06](https://github.com/open-feature/java-sdk/commit/6f67b06f712c461f331681a76f5cb2c3ddb0d36b))
* **deps:** update github/codeql-action digest to ac30a39 ([#1488](https://github.com/open-feature/java-sdk/issues/1488)) ([8fad544](https://github.com/open-feature/java-sdk/commit/8fad544b17ee08b4280d7975073d00a874c374db))
* **deps:** update github/codeql-action digest to b1e4dc3 ([#1471](https://github.com/open-feature/java-sdk/issues/1471)) ([2dcd6a1](https://github.com/open-feature/java-sdk/commit/2dcd6a1dd0c80ee676b9860afd6a6002d0ea4aea))
* **deps:** update github/codeql-action digest to b694213 ([#1503](https://github.com/open-feature/java-sdk/issues/1503)) ([a5d1cbc](https://github.com/open-feature/java-sdk/commit/a5d1cbced4658fadb63f362b4512bdbd68ae7d6a))
* **deps:** update github/codeql-action digest to b86edfc ([#1453](https://github.com/open-feature/java-sdk/issues/1453)) ([b667aa3](https://github.com/open-feature/java-sdk/commit/b667aa325136b78c01867d40342f81eeb7e16f46))
* **deps:** update github/codeql-action digest to bc02a25 ([#1460](https://github.com/open-feature/java-sdk/issues/1460)) ([5e922cf](https://github.com/open-feature/java-sdk/commit/5e922cf3efc156135563707de92e508b0a4d19f3))
* **deps:** update github/codeql-action digest to be30325 ([#1479](https://github.com/open-feature/java-sdk/issues/1479)) ([844d5e2](https://github.com/open-feature/java-sdk/commit/844d5e244b02703b624cf75e5bf8448c07e62d3d))
* **deps:** update github/codeql-action digest to dcc1a66 ([#1499](https://github.com/open-feature/java-sdk/issues/1499)) ([69519b1](https://github.com/open-feature/java-sdk/commit/69519b1ef7274ceae39d6746c5a5a98dc69f562f))
* **deps:** update github/codeql-action digest to ef36b69 ([#1484](https://github.com/open-feature/java-sdk/issues/1484)) ([8bf777a](https://github.com/open-feature/java-sdk/commit/8bf777a7e99be4dfac8917b8e61cb6c23385b8ce))
* **deps:** update io.cucumber.version to v7.23.0 ([#1465](https://github.com/open-feature/java-sdk/issues/1465)) ([2de7616](https://github.com/open-feature/java-sdk/commit/2de76166764bacd34883b13220dd0bad824c8b1a))
* improvements to release workflow ([#1451](https://github.com/open-feature/java-sdk/issues/1451)) ([1714efe](https://github.com/open-feature/java-sdk/commit/1714efe81aa6ae025f4f8b12c9c042561498d25e))
* migrate to new publish ([5425a34](https://github.com/open-feature/java-sdk/commit/5425a34a12baa04f9583b83fd1bfdd7e2a6ab5e8))
* remove unneeded version information ([#1428](https://github.com/open-feature/java-sdk/issues/1428)) ([3ed65cf](https://github.com/open-feature/java-sdk/commit/3ed65cfb0cb5ee5b70793cd68a27909c81cd4fab))
* skip tests on publish ([6194186](https://github.com/open-feature/java-sdk/commit/6194186b3e791f3cb28da24f5acb3ff96788d65e))
* update publish env vars ([85d89ee](https://github.com/open-feature/java-sdk/commit/85d89ee79a52d960322731fb786c0f60245f0d75))
## [1.15.1](https://github.com/open-feature/java-sdk/compare/v1.14.2...v1.15.1) (2025-05-14)
### NOTABLE CHANGES
* Raise required Java version to 11 ([#1393](https://github.com/open-feature/java-sdk/issues/1393))
### 🐛 Bug Fixes
* **deps:** update dependency io.cucumber:cucumber-bom to v7.22.0 ([#1411](https://github.com/open-feature/java-sdk/issues/1411)) ([e251819](https://github.com/open-feature/java-sdk/commit/e25181982af8e5d37be4876b71b337ca86e8454b))
* **deps:** update dependency io.cucumber:cucumber-bom to v7.22.1 ([#1427](https://github.com/open-feature/java-sdk/issues/1427)) ([1c4d2ef](https://github.com/open-feature/java-sdk/commit/1c4d2efafdebb562f099ba1ec3a6a29eabc8ff91))
* **deps:** update dependency io.cucumber:cucumber-bom to v7.22.2 ([#1442](https://github.com/open-feature/java-sdk/issues/1442)) ([e568f3a](https://github.com/open-feature/java-sdk/commit/e568f3a4f560187586d5473aa7bc12a673340e24))
* **deps:** update dependency org.projectlombok:lombok to v1.18.38 ([#1403](https://github.com/open-feature/java-sdk/issues/1403)) ([ef32f11](https://github.com/open-feature/java-sdk/commit/ef32f11571de4d3a981efec4f61113eb8b0d7d9d))
* **deps:** update junit5 monorepo ([#1418](https://github.com/open-feature/java-sdk/issues/1418)) ([97b442e](https://github.com/open-feature/java-sdk/commit/97b442ed6e8f2b99ca949ffd63e5cbf57718c796))
### ✨ New Features
* add logging on provider state transitions ([#1444](https://github.com/open-feature/java-sdk/issues/1444)) ([e2813b2](https://github.com/open-feature/java-sdk/commit/e2813b2e5df8e548caf16e3e425b35962045ca6c))
* add telemetry helper utils ([#1346](https://github.com/open-feature/java-sdk/issues/1346)) ([d0ae548](https://github.com/open-feature/java-sdk/commit/d0ae5482771f4d1701bce25381cdf4e92e2d4882))
* Raise required Java version to 11 ([#1393](https://github.com/open-feature/java-sdk/issues/1393)) ([4dc988b](https://github.com/open-feature/java-sdk/commit/4dc988b637a9e9c377edf7df7b29bf6407319f16))
### 🧹 Chore
* add DCO to release please ([45ec4b1](https://github.com/open-feature/java-sdk/commit/45ec4b1b7734c9117f43abf8fe5105c2903c3986))
* add DCO to release please ([#1429](https://github.com/open-feature/java-sdk/issues/1429)) ([32137bf](https://github.com/open-feature/java-sdk/commit/32137bfa82e9c0391c999bf0be2a36f201620931))
* add publish env ([#1420](https://github.com/open-feature/java-sdk/issues/1420)) ([665dd51](https://github.com/open-feature/java-sdk/commit/665dd51eb2b3b79d3ffccb6cef64d544aa5e7206))
* **deps:** update actions/setup-java digest to 148017a ([#1404](https://github.com/open-feature/java-sdk/issues/1404)) ([f834e11](https://github.com/open-feature/java-sdk/commit/f834e11acc7ecf903e972d80e9dab324be97847e))
* **deps:** update actions/setup-java digest to c5195ef ([#1415](https://github.com/open-feature/java-sdk/issues/1415)) ([a578903](https://github.com/open-feature/java-sdk/commit/a5789038acc36cb2b0ddf12e534a1317e1c9b8e8))
* **deps:** update actions/setup-java digest to f4f1212 ([#1421](https://github.com/open-feature/java-sdk/issues/1421)) ([a3e2a59](https://github.com/open-feature/java-sdk/commit/a3e2a59aebee051ae8c7eb1c5769a04dc9da8de3))
* **deps:** update amannn/action-semantic-pull-request digest to 3352882 ([#1434](https://github.com/open-feature/java-sdk/issues/1434)) ([62ba6db](https://github.com/open-feature/java-sdk/commit/62ba6db457358d759fe83f23318b1cf4200756ac))
* **deps:** update codecov/codecov-action action to v5.4.2 ([#1419](https://github.com/open-feature/java-sdk/issues/1419)) ([a6389e8](https://github.com/open-feature/java-sdk/commit/a6389e89f60aa7f4871f47d78fedd27a7f9991b4))
* **deps:** update dependency com.diffplug.spotless:spotless-maven-plugin to v2.44.4 ([#1414](https://github.com/open-feature/java-sdk/issues/1414)) ([e066d3f](https://github.com/open-feature/java-sdk/commit/e066d3f749c09bb1ef79e3bcace1d205a39787df))
* **deps:** update dependency com.h3xstream.findsecbugs:findsecbugs-plugin to v1.14.0 ([#1422](https://github.com/open-feature/java-sdk/issues/1422)) ([495da27](https://github.com/open-feature/java-sdk/commit/495da271bee976a942973cd23012f60db895bf24))
* **deps:** update dependency com.puppycrawl.tools:checkstyle to v10 ([#103](https://github.com/open-feature/java-sdk/issues/103)) ([3403510](https://github.com/open-feature/java-sdk/commit/34035105154b7945c02de2a88fe83eb2414526ef))
* **deps:** update dependency com.tngtech.archunit:archunit-junit5 to v1.4.1 ([#1440](https://github.com/open-feature/java-sdk/issues/1440)) ([78657ee](https://github.com/open-feature/java-sdk/commit/78657ee79efdc94018387cdf8263a73d4abf7191))
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.5 ([#1400](https://github.com/open-feature/java-sdk/issues/1400)) ([1f2d071](https://github.com/open-feature/java-sdk/commit/1f2d0715087ebd4554826d8552b250e4b8b950c8))
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.5 ([#1401](https://github.com/open-feature/java-sdk/issues/1401)) ([07301bd](https://github.com/open-feature/java-sdk/commit/07301bda3f5b65550eff1e025fc9c0bec3c25275))
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.5.3 ([#1398](https://github.com/open-feature/java-sdk/issues/1398)) ([1fcf0e7](https://github.com/open-feature/java-sdk/commit/1fcf0e77d956c88c54e10942d96d2afd4d79315c))
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.3 ([#1399](https://github.com/open-feature/java-sdk/issues/1399)) ([d6ebc16](https://github.com/open-feature/java-sdk/commit/d6ebc161a93ad703e25592abdb0bf0fd9e281bbc))
* **deps:** update dependency org.jacoco:jacoco-maven-plugin to v0.8.13 ([#1407](https://github.com/open-feature/java-sdk/issues/1407)) ([e19ccaa](https://github.com/open-feature/java-sdk/commit/e19ccaa35d9ac4d89d72ea58a70d416d202078db))
* **deps:** update dependency org.mockito:mockito-core to v5.17.0 ([#1409](https://github.com/open-feature/java-sdk/issues/1409)) ([345cdcf](https://github.com/open-feature/java-sdk/commit/345cdcfa10da64c61d769746f335f38ac564e9ad))
* **deps:** update github/codeql-action digest to 15bce5b ([#1443](https://github.com/open-feature/java-sdk/issues/1443)) ([bc10bac](https://github.com/open-feature/java-sdk/commit/bc10bacb5a68d0d2e498cb41c087505490f19de8))
* **deps:** update github/codeql-action digest to 2a8cbad ([#1423](https://github.com/open-feature/java-sdk/issues/1423)) ([6b6849f](https://github.com/open-feature/java-sdk/commit/6b6849f3a3ee8a7b66d859c8e522bc101d1ccd44))
* **deps:** update github/codeql-action digest to 362ef4c ([#1408](https://github.com/open-feature/java-sdk/issues/1408)) ([ca160ca](https://github.com/open-feature/java-sdk/commit/ca160cab7ccd71527e06a0851502353ac50b8d0d))
* **deps:** update github/codeql-action digest to 40e16ed ([#1437](https://github.com/open-feature/java-sdk/issues/1437)) ([f965cbc](https://github.com/open-feature/java-sdk/commit/f965cbcb37d20724e15b76c15842a88574810b1a))
* **deps:** update github/codeql-action digest to 4c3e536 ([#1417](https://github.com/open-feature/java-sdk/issues/1417)) ([0c77c84](https://github.com/open-feature/java-sdk/commit/0c77c8446032eaac7e068d48901e1423c21db326))
* **deps:** update github/codeql-action digest to 4ffa236 ([#1425](https://github.com/open-feature/java-sdk/issues/1425)) ([a7828e7](https://github.com/open-feature/java-sdk/commit/a7828e73a8f2e30f71bd2d9d4da180b2fa436424))
* **deps:** update github/codeql-action digest to 56dd02f ([#1416](https://github.com/open-feature/java-sdk/issues/1416)) ([4607c62](https://github.com/open-feature/java-sdk/commit/4607c62f15f7ee572207b8ec012ad4b3626e0184))
* **deps:** update github/codeql-action digest to 5eb3ed6 ([#1439](https://github.com/open-feature/java-sdk/issues/1439)) ([f2348ea](https://github.com/open-feature/java-sdk/commit/f2348ea370412351389c60eef390f36edbea68b0))
* **deps:** update github/codeql-action digest to 83605b3 ([#1435](https://github.com/open-feature/java-sdk/issues/1435)) ([7e74f2a](https://github.com/open-feature/java-sdk/commit/7e74f2aa3ad2dc8f7a3e4ad398e7705b3e3db364))
* **deps:** update github/codeql-action digest to 97a2bfd ([#1438](https://github.com/open-feature/java-sdk/issues/1438)) ([85b200a](https://github.com/open-feature/java-sdk/commit/85b200a08b9f8a71de3b5a19eaa057ec04e0801e))
* **deps:** update github/codeql-action digest to 9f45e74 ([#1396](https://github.com/open-feature/java-sdk/issues/1396)) ([37d76be](https://github.com/open-feature/java-sdk/commit/37d76be697e83f524250a82b2a67cdb4a953d7bc))
* **deps:** update github/codeql-action digest to d26c46a ([#1413](https://github.com/open-feature/java-sdk/issues/1413)) ([5b327ee](https://github.com/open-feature/java-sdk/commit/5b327eeb770d0a4222f3599be79543b7bed9abc2))
* **deps:** update github/codeql-action digest to dab8a02 ([#1405](https://github.com/open-feature/java-sdk/issues/1405)) ([5b2f151](https://github.com/open-feature/java-sdk/commit/5b2f1513ab75ef6692978830e59eba87ffa494d5))
* **deps:** update github/codeql-action digest to e13fe0d ([#1406](https://github.com/open-feature/java-sdk/issues/1406)) ([e211397](https://github.com/open-feature/java-sdk/commit/e211397d517e1263e1251f9c99093bf05cecd93f))
* **deps:** update github/codeql-action digest to ed51cb5 ([#1436](https://github.com/open-feature/java-sdk/issues/1436)) ([b09e887](https://github.com/open-feature/java-sdk/commit/b09e88798fed529161c61b96c20a8f257d355d3c))
* **deps:** update github/codeql-action digest to efffb48 ([#1402](https://github.com/open-feature/java-sdk/issues/1402)) ([384953d](https://github.com/open-feature/java-sdk/commit/384953d30ecff83d60a2e5b9790e8228d1a52ac7))
* **deps:** update github/codeql-action digest to f843d94 ([#1432](https://github.com/open-feature/java-sdk/issues/1432)) ([99faaf8](https://github.com/open-feature/java-sdk/commit/99faaf88aa07bd45fc473db5bafce3b8eafaf9e0))
* **deps:** update io.cucumber.version to v7.22.0 ([#1410](https://github.com/open-feature/java-sdk/issues/1410)) ([3c69f2f](https://github.com/open-feature/java-sdk/commit/3c69f2f36c4e975d690ecc2e790df632a33001ba))
* **deps:** update io.cucumber.version to v7.22.1 ([#1426](https://github.com/open-feature/java-sdk/issues/1426)) ([844374a](https://github.com/open-feature/java-sdk/commit/844374a42b94deffab6856e978766354a6f46576))
* **deps:** update io.cucumber.version to v7.22.2 ([#1441](https://github.com/open-feature/java-sdk/issues/1441)) ([58454b4](https://github.com/open-feature/java-sdk/commit/58454b4eaabfd3327f7ceaff4bf335a5a839ed41))
* **main:** release 1.15.0 ([#1431](https://github.com/open-feature/java-sdk/issues/1431)) ([7182a7f](https://github.com/open-feature/java-sdk/commit/7182a7fc4197e70218e829971dae2cff09f948c9))
* update boostrap sha for release please ([f6bd30d](https://github.com/open-feature/java-sdk/commit/f6bd30db93e37e596d211d899315a62d9f810199))
* update codeowners to give global maintainers code ownership ([#1412](https://github.com/open-feature/java-sdk/issues/1412)) ([498fd38](https://github.com/open-feature/java-sdk/commit/498fd382659669315b0db61db5f19ce054467bc9))
* update release please action ([#1430](https://github.com/open-feature/java-sdk/issues/1430)) ([1cc851b](https://github.com/open-feature/java-sdk/commit/1cc851b293008a8dd273e904e4c77a650ad71146))
* use PAT for release please ([014f8a5](https://github.com/open-feature/java-sdk/commit/014f8a59da8f1e976e440ed1ea17e85561f98e2d))
### 📚 Documentation
* add try-catch example for setProviderAndWait usage ([#1433](https://github.com/open-feature/java-sdk/issues/1433)) ([96cf9c7](https://github.com/open-feature/java-sdk/commit/96cf9c7f5463e4e0de394117845aebdd9a69425f))
## [1.14.2](https://github.com/open-feature/java-sdk/compare/v1.14.1...v1.14.2) (2025-03-27)

View File

@ -3,4 +3,4 @@
#
# Managed by Peribolos: https://github.com/open-feature/community/blob/main/config/open-feature/sdk-java/workgroup.yaml
#
* @open-feature/sdk-java-maintainers
* @open-feature/sdk-java-maintainers @open-feature/maintainers

View File

@ -18,8 +18,8 @@
</a>
<!-- x-release-please-start-version -->
<a href="https://github.com/open-feature/java-sdk/releases/tag/v1.14.2">
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.14.2&color=blue&style=for-the-badge" />
<a href="https://github.com/open-feature/java-sdk/releases/tag/v1.16.0">
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.16.0&color=blue&style=for-the-badge" />
</a>
<!-- x-release-please-end -->
@ -46,7 +46,7 @@
### Requirements
- Java 8+ (compiler target is 1.8)
- Java 11+ (compiler target is 11)
Note that this library is intended to be used in server-side contexts and has not been evaluated for use on mobile devices.
@ -59,7 +59,7 @@ Note that this library is intended to be used in server-side contexts and has no
<dependency>
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.14.2</version>
<version>1.16.0</version>
</dependency>
```
<!-- x-release-please-end-version -->
@ -84,7 +84,7 @@ If you would like snapshot builds, this is the relevant repository information:
<!-- x-release-please-start-version -->
```groovy
dependencies {
implementation 'dev.openfeature:sdk:1.14.2'
implementation 'dev.openfeature:sdk:1.16.0'
}
```
<!-- x-release-please-end-version -->
@ -104,7 +104,12 @@ public void example(){
// configure a provider
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(new InMemoryProvider(myFlags));
try {
api.setProviderAndWait(new InMemoryProvider(myFlags));
} catch (Exception e) {
// handle initialization failure
e.printStackTrace();
}
// create a client
Client client = api.getClient();
@ -149,7 +154,12 @@ To register a provider in a blocking manner to ensure it is ready before further
```java
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(new MyProvider());
try {
api.setProviderAndWait(new MyProvider());
} catch (Exception e) {
// handle initialization failure
e.printStackTrace();
}
```
#### Asynchronous

77
pom.xml
View File

@ -5,22 +5,20 @@
<groupId>dev.openfeature</groupId>
<artifactId>sdk</artifactId>
<version>1.14.2</version> <!--x-release-please-version -->
<version>1.16.0</version> <!--x-release-please-version -->
<properties>
<toolchain.jdk.version>[17,)</toolchain.jdk.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
<junit.jupiter.version>5.12.1</junit.jupiter.version>
<io.cucumber.version>7.21.1</io.cucumber.version>
<org.mockito.version>5.16.1</org.mockito.version>
<org.mockito.version>5.18.0</org.mockito.version>
<!-- exclusion expression for e2e tests -->
<testExclusions>**/e2e/*.java</testExclusions>
<module-name>${project.groupId}.${project.artifactId}</module-name>
<skip.tests>false</skip.tests>
<!-- this will throw an error if we use wrong apis -->
<maven.compiler.release>8</maven.compiler.release>
<maven.compiler.release>11</maven.compiler.release>
</properties>
<name>OpenFeature Java SDK</name>
@ -54,7 +52,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
@ -76,7 +74,7 @@
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>1.4.0</version>
<version>1.4.1</version>
<scope>test</scope>
</dependency>
@ -97,56 +95,48 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>${io.cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>${io.cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${io.cucumber.version}</version>
<scope>test</scope>
</dependency>
@ -160,7 +150,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.0-jre</version>
<version>33.4.8-jre</version>
<scope>test</scope>
</dependency>
@ -189,14 +179,14 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.4</version>
<version>1.17.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.17.4</version>
<version>1.17.6</version>
<scope>test</scope>
</dependency>
<!-- End mockito workaround-->
@ -204,7 +194,7 @@
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-bom</artifactId>
<version>7.21.1</version>
<version>7.26.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -212,7 +202,7 @@
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.12.1</version>
<version>5.13.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -268,7 +258,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<version>3.5.3</version>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
@ -287,7 +277,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.2</version>
<version>3.5.3</version>
<configuration>
<argLine>
${surefireArgLine}
@ -354,7 +344,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<version>0.8.13</version>
<executions>
<execution>
@ -413,14 +403,14 @@
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>4.9.3.0</version>
<version>4.9.3.2</version>
<configuration>
<excludeFilterFile>spotbugs-exclusions.xml</excludeFilterFile>
<plugins>
<plugin>
<groupId>com.h3xstream.findsecbugs</groupId>
<artifactId>findsecbugs-plugin</artifactId>
<version>1.13.0</version>
<version>1.14.0</version>
</plugin>
</plugins>
</configuration>
@ -457,7 +447,7 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>9.3</version>
<version>10.26.1</version>
</dependency>
</dependencies>
<executions>
@ -473,7 +463,7 @@
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.44.3</version>
<version>2.45.0</version>
<configuration>
<!-- optional: limit format enforcement to just the files changed by this feature branch -->
<!-- <ratchetFrom>origin/main</ratchetFrom>-->
@ -530,14 +520,13 @@
<plugins>
<!-- Begin publish to maven central -->
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.7.0</version>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.8.0</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
<!-- End publish to maven central -->
@ -581,7 +570,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.7</version>
<version>3.2.8</version>
<executions>
<execution>
<id>sign-artifacts</id>
@ -622,7 +611,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.0</version>
<version>3.5.1</version>
<executions>
<execution>
<id>update-test-harness-submodule</id>
@ -646,14 +635,14 @@
</plugins>
</build>
</profile>
<!-- profile for running tests under java 8 (used mostly in CI) -->
<!-- selected automatically by JDK activeation (see https://maven.apache.org/guides/introduction/introduction-to-profiles.html#implicit-profile-activation) -->
<!-- profile for running tests under java 11 (used mostly in CI) -->
<!-- selected automatically by JDK activation (see https://maven.apache.org/guides/introduction/introduction-to-profiles.html#implicit-profile-activation) -->
<profile>
<id>java8</id>
<id>java11</id>
<!-- with the next block we can define a set of sdks which still support java 8, if any of the sdks is not supporting java 8 anymore -->
<!--<modules><module></module></modules>-->
<properties>
<toolchain.jdk.version>(1.8,9)</toolchain.jdk.version>
<toolchain.jdk.version>[11,)</toolchain.jdk.version>
<skip.tests>true</skip.tests>
</properties>
@ -674,7 +663,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<version>3.5.3</version>
<configuration>
<argLine>
${surefireArgLine}
@ -690,7 +679,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.2</version>
<version>3.5.3</version>
<configuration>
<argLine>
${surefireArgLine}
@ -721,8 +710,8 @@
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots</url>
<id>central</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>

View File

@ -1,5 +1,6 @@
{
"bootstrap-sha": "c701a6c4ebbe1170a25ca7636a31508b9628831c",
"bootstrap-sha": "d7b591c9f910afad303d6d814f65c7f9dab33b89",
"signoff": "OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com>",
"packages": {
".": {
"package-name": "dev.openfeature.sdk",

View File

@ -5,5 +5,10 @@
<username>${env.OSSRH_USERNAME}</username>
<password>${env.OSSRH_PASSWORD}</password>
</server>
<server>
<id>central</id>
<username>${env.CENTRAL_USERNAME}</username>
<password>${env.CENTRAL_PASSWORD}</password>
</server>
</servers>
</settings>

View File

@ -0,0 +1,44 @@
package dev.openfeature.sdk;
/**
* A class to help with synchronization by allowing the optional awaiting of the associated action.
*/
public class Awaitable {
/**
* An already-completed Awaitable. Awaiting this will return immediately.
*/
public static final Awaitable FINISHED = new Awaitable(true);
private boolean isDone = false;
public Awaitable() {}
private Awaitable(boolean isDone) {
this.isDone = isDone;
}
/**
* Lets the calling thread wait until some other thread calls {@link Awaitable#wakeup()}. If
* {@link Awaitable#wakeup()} has been called before the current thread invokes this method, it will return
* immediately.
*/
@SuppressWarnings("java:S2142")
public synchronized void await() {
while (!isDone) {
try {
this.wait();
} catch (InterruptedException ignored) {
// ignored, do not propagate the interrupted state
}
}
}
/**
* Wakes up all threads that have called {@link Awaitable#await()} and lets them proceed.
*/
public synchronized void wakeup() {
isDone = true;
this.notifyAll();
}
}

View File

@ -0,0 +1,24 @@
package dev.openfeature.sdk;
import java.util.HashMap;
import java.util.Map;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
/**
* Represents an evaluation event.
*/
@Builder
@Getter
public class EvaluationEvent {
private String name;
@Singular("attribute")
private Map<String, Object> attributes;
public Map<String, Object> getAttributes() {
return new HashMap<>(attributes);
}
}

View File

@ -76,15 +76,32 @@ public abstract class EventProvider implements FeatureProvider {
* @param event The event type
* @param details The details of the event
*/
public void emit(ProviderEvent event, ProviderEventDetails details) {
if (eventProviderListener != null) {
eventProviderListener.onEmit(event, details);
public Awaitable emit(final ProviderEvent event, final ProviderEventDetails details) {
final var localEventProviderListener = this.eventProviderListener;
final var localOnEmit = this.onEmit;
if (localEventProviderListener == null && localOnEmit == null) {
return Awaitable.FINISHED;
}
final TriConsumer<EventProvider, ProviderEvent, ProviderEventDetails> localOnEmit = this.onEmit;
if (localOnEmit != null) {
emitterExecutor.submit(() -> localOnEmit.accept(this, event, details));
}
final var awaitable = new Awaitable();
// These calls need to be executed on a different thread to prevent deadlocks when the provider initialization
// relies on a ready event to be emitted
emitterExecutor.submit(() -> {
try (var ignored = OpenFeatureAPI.lock.readLockAutoCloseable()) {
if (localEventProviderListener != null) {
localEventProviderListener.onEmit(event, details);
}
if (localOnEmit != null) {
localOnEmit.accept(this, event, details);
}
} finally {
awaitable.wakeup();
}
});
return awaitable;
}
/**
@ -93,8 +110,8 @@ public abstract class EventProvider implements FeatureProvider {
*
* @param details The details of the event
*/
public void emitProviderReady(ProviderEventDetails details) {
emit(ProviderEvent.PROVIDER_READY, details);
public Awaitable emitProviderReady(ProviderEventDetails details) {
return emit(ProviderEvent.PROVIDER_READY, details);
}
/**
@ -104,8 +121,8 @@ public abstract class EventProvider implements FeatureProvider {
*
* @param details The details of the event
*/
public void emitProviderConfigurationChanged(ProviderEventDetails details) {
emit(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, details);
public Awaitable emitProviderConfigurationChanged(ProviderEventDetails details) {
return emit(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, details);
}
/**
@ -114,8 +131,8 @@ public abstract class EventProvider implements FeatureProvider {
*
* @param details The details of the event
*/
public void emitProviderStale(ProviderEventDetails details) {
emit(ProviderEvent.PROVIDER_STALE, details);
public Awaitable emitProviderStale(ProviderEventDetails details) {
return emit(ProviderEvent.PROVIDER_STALE, details);
}
/**
@ -124,7 +141,7 @@ public abstract class EventProvider implements FeatureProvider {
*
* @param details The details of the event
*/
public void emitProviderError(ProviderEventDetails details) {
emit(ProviderEvent.PROVIDER_ERROR, details);
public Awaitable emitProviderError(ProviderEventDetails details) {
return emit(ProviderEvent.PROVIDER_ERROR, details);
}
}

View File

@ -1,12 +1,12 @@
package dev.openfeature.sdk;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@ -23,13 +23,10 @@ class EventSupport {
// we use a v4 uuid as a "placeholder" for anonymous clients, since
// ConcurrentHashMap doesn't support nulls
private static final String defaultClientUuid = UUID.randomUUID().toString();
private static final String DEFAULT_CLIENT_UUID = UUID.randomUUID().toString();
private final Map<String, HandlerStore> handlerStores = new ConcurrentHashMap<>();
private final HandlerStore globalHandlerStore = new HandlerStore();
private final ExecutorService taskExecutor = Executors.newCachedThreadPool(runnable -> {
final Thread thread = new Thread(runnable);
return thread;
});
private final ExecutorService taskExecutor = Executors.newCachedThreadPool();
/**
* Run all the event handlers associated with this domain.
@ -40,11 +37,10 @@ class EventSupport {
* @param eventDetails the event details
*/
public void runClientHandlers(String domain, ProviderEvent event, EventDetails eventDetails) {
domain = Optional.ofNullable(domain).orElse(defaultClientUuid);
domain = Optional.ofNullable(domain).orElse(DEFAULT_CLIENT_UUID);
// run handlers if they exist
Optional.ofNullable(handlerStores.get(domain))
.filter(store -> Optional.of(store).isPresent())
.map(store -> store.handlerMap.get(event))
.ifPresent(handlers -> handlers.forEach(handler -> runHandler(handler, eventDetails)));
}
@ -69,7 +65,7 @@ class EventSupport {
* @param handler the handler function to run
*/
public void addClientHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
final String name = Optional.ofNullable(domain).orElse(defaultClientUuid);
final String name = Optional.ofNullable(domain).orElse(DEFAULT_CLIENT_UUID);
// lazily create and cache a HandlerStore if it doesn't exist
HandlerStore store = Optional.ofNullable(this.handlerStores.get(name)).orElseGet(() -> {
@ -89,7 +85,7 @@ class EventSupport {
* @param handler the handler ref to be removed
*/
public void removeClientHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
domain = Optional.ofNullable(domain).orElse(defaultClientUuid);
domain = Optional.ofNullable(domain).orElse(DEFAULT_CLIENT_UUID);
this.handlerStores.get(domain).removeHandler(event, handler);
}
@ -160,14 +156,14 @@ class EventSupport {
// instantiated when a handler is added to that client.
static class HandlerStore {
private final Map<ProviderEvent, List<Consumer<EventDetails>>> handlerMap;
private final Map<ProviderEvent, Collection<Consumer<EventDetails>>> handlerMap;
HandlerStore() {
handlerMap = new ConcurrentHashMap<>();
handlerMap.put(ProviderEvent.PROVIDER_READY, new ArrayList<>());
handlerMap.put(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, new ArrayList<>());
handlerMap.put(ProviderEvent.PROVIDER_ERROR, new ArrayList<>());
handlerMap.put(ProviderEvent.PROVIDER_STALE, new ArrayList<>());
handlerMap.put(ProviderEvent.PROVIDER_READY, new ConcurrentLinkedQueue<>());
handlerMap.put(ProviderEvent.PROVIDER_CONFIGURATION_CHANGED, new ConcurrentLinkedQueue<>());
handlerMap.put(ProviderEvent.PROVIDER_ERROR, new ConcurrentLinkedQueue<>());
handlerMap.put(ProviderEvent.PROVIDER_STALE, new ConcurrentLinkedQueue<>());
}
void addHandler(ProviderEvent event, Consumer<EventDetails> handler) {

View File

@ -30,6 +30,7 @@ public interface FeatureProvider {
* can overwrite this method,
* if they have special initialization needed prior being called for flag
* evaluation.
*
* <p>
* It is ok if the method is expensive as it is executed in the background. All
* runtime exceptions will be
@ -45,6 +46,7 @@ public interface FeatureProvider {
* flags, or the SDK is shut down.
* Providers can overwrite this method, if they have special shutdown actions
* needed.
*
* <p>
* It is ok if the method is expensive as it is executed in the background. All
* runtime exceptions will be

View File

@ -2,14 +2,14 @@ package dev.openfeature.sdk;
import dev.openfeature.sdk.exceptions.OpenFeatureError;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.Getter;
import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;
@Slf4j
class FeatureProviderStateManager implements EventProviderListener {
private final FeatureProvider delegate;
private final AtomicBoolean isInitialized = new AtomicBoolean();
@Getter
private ProviderState state = ProviderState.NOT_READY;
private final AtomicReference<ProviderState> state = new AtomicReference<>(ProviderState.NOT_READY);
public FeatureProviderStateManager(FeatureProvider delegate) {
this.delegate = delegate;
@ -24,17 +24,17 @@ class FeatureProviderStateManager implements EventProviderListener {
}
try {
delegate.initialize(evaluationContext);
state = ProviderState.READY;
setState(ProviderState.READY);
} catch (OpenFeatureError openFeatureError) {
if (ErrorCode.PROVIDER_FATAL.equals(openFeatureError.getErrorCode())) {
state = ProviderState.FATAL;
setState(ProviderState.FATAL);
} else {
state = ProviderState.ERROR;
setState(ProviderState.ERROR);
}
isInitialized.set(false);
throw openFeatureError;
} catch (Exception e) {
state = ProviderState.ERROR;
setState(ProviderState.ERROR);
isInitialized.set(false);
throw e;
}
@ -42,7 +42,7 @@ class FeatureProviderStateManager implements EventProviderListener {
public void shutdown() {
delegate.shutdown();
state = ProviderState.NOT_READY;
setState(ProviderState.NOT_READY);
isInitialized.set(false);
}
@ -50,17 +50,34 @@ class FeatureProviderStateManager implements EventProviderListener {
public void onEmit(ProviderEvent event, ProviderEventDetails details) {
if (ProviderEvent.PROVIDER_ERROR.equals(event)) {
if (details != null && details.getErrorCode() == ErrorCode.PROVIDER_FATAL) {
state = ProviderState.FATAL;
setState(ProviderState.FATAL);
} else {
state = ProviderState.ERROR;
setState(ProviderState.ERROR);
}
} else if (ProviderEvent.PROVIDER_STALE.equals(event)) {
state = ProviderState.STALE;
setState(ProviderState.STALE);
} else if (ProviderEvent.PROVIDER_READY.equals(event)) {
state = ProviderState.READY;
setState(ProviderState.READY);
}
}
private void setState(ProviderState state) {
ProviderState oldState = this.state.getAndSet(state);
if (oldState != state) {
String providerName;
if (delegate.getMetadata() == null || delegate.getMetadata().getName() == null) {
providerName = "unknown";
} else {
providerName = delegate.getMetadata().getName();
}
log.info("Provider {} transitioned from state {} to state {}", providerName, oldState, state);
}
}
public ProviderState getState() {
return state.get();
}
FeatureProvider getProvider() {
return delegate;
}

View File

@ -5,9 +5,12 @@ import dev.openfeature.sdk.internal.AutoCloseableLock;
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
@ -21,14 +24,14 @@ import lombok.extern.slf4j.Slf4j;
public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
// package-private multi-read/single-write lock
static AutoCloseableReentrantReadWriteLock lock = new AutoCloseableReentrantReadWriteLock();
private final List<Hook> apiHooks;
private final ConcurrentLinkedQueue<Hook> apiHooks;
private ProviderRepository providerRepository;
private EventSupport eventSupport;
private EvaluationContext evaluationContext;
private final AtomicReference<EvaluationContext> evaluationContext = new AtomicReference<>();
private TransactionContextPropagator transactionContextPropagator;
protected OpenFeatureAPI() {
apiHooks = new ArrayList<>();
apiHooks = new ConcurrentLinkedQueue<>();
providerRepository = new ProviderRepository(this);
eventSupport = new EventSupport();
transactionContextPropagator = new NoOpTransactionContextPropagator();
@ -115,9 +118,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* @return api instance
*/
public OpenFeatureAPI setEvaluationContext(EvaluationContext evaluationContext) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
this.evaluationContext = evaluationContext;
}
this.evaluationContext.set(evaluationContext);
return this;
}
@ -127,16 +128,14 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* @return evaluation context
*/
public EvaluationContext getEvaluationContext() {
try (AutoCloseableLock __ = lock.readLockAutoCloseable()) {
return this.evaluationContext;
}
return evaluationContext.get();
}
/**
* Return the transaction context propagator.
*/
public TransactionContextPropagator getTransactionContextPropagator() {
try (AutoCloseableLock __ = lock.readLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.readLockAutoCloseable()) {
return this.transactionContextPropagator;
}
}
@ -150,7 +149,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
if (transactionContextPropagator == null) {
throw new IllegalArgumentException("Transaction context propagator cannot be null");
}
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
this.transactionContextPropagator = transactionContextPropagator;
}
}
@ -176,7 +175,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* Set the default provider.
*/
public void setProvider(FeatureProvider provider) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
providerRepository.setProvider(
provider,
this::attachEventProvider,
@ -194,7 +193,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* @param provider The provider to set.
*/
public void setProvider(String domain, FeatureProvider provider) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
providerRepository.setProvider(
domain,
provider,
@ -207,10 +206,16 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
}
/**
* Set the default provider and wait for initialization to finish.
* Sets the default provider and waits for its initialization to complete.
*
* <p>Note: If the provider fails during initialization, an {@link OpenFeatureError} will be thrown.
* It is recommended to wrap this call in a try-catch block to handle potential initialization failures gracefully.
*
* @param provider the {@link FeatureProvider} to set as the default.
* @throws OpenFeatureError if the provider fails during initialization.
*/
public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
providerRepository.setProvider(
provider,
this::attachEventProvider,
@ -224,11 +229,15 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
/**
* Add a provider for a domain and wait for initialization to finish.
*
* <p>Note: If the provider fails during initialization, an {@link OpenFeatureError} will be thrown.
* It is recommended to wrap this call in a try-catch block to handle potential initialization failures gracefully.
*
* @param domain The domain to bind the provider to.
* @param provider The provider to set.
* @throws OpenFeatureError if the provider fails during initialization.
*/
public void setProviderAndWait(String domain, FeatureProvider provider) throws OpenFeatureError {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
providerRepository.setProvider(
domain,
provider,
@ -242,9 +251,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
private void attachEventProvider(FeatureProvider provider) {
if (provider instanceof EventProvider) {
((EventProvider) provider).attach((p, event, details) -> {
runHandlersForProvider(p, event, details);
});
((EventProvider) provider).attach(this::runHandlersForProvider);
}
}
@ -297,9 +304,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* @param hooks The hook to add.
*/
public void addHooks(Hook... hooks) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
this.apiHooks.addAll(Arrays.asList(hooks));
}
this.apiHooks.addAll(Arrays.asList(hooks));
}
/**
@ -308,18 +313,23 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* @return A list of {@link Hook}s.
*/
public List<Hook> getHooks() {
try (AutoCloseableLock __ = lock.readLockAutoCloseable()) {
return this.apiHooks;
}
return new ArrayList<>(this.apiHooks);
}
/**
* Returns a reference to the collection of {@link Hook}s.
*
* @return The collection of {@link Hook}s.
*/
Collection<Hook> getMutableHooks() {
return this.apiHooks;
}
/**
* Removes all hooks.
*/
public void clearHooks() {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
this.apiHooks.clear();
}
this.apiHooks.clear();
}
/**
@ -329,7 +339,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* Once shut down is complete, API is reset and ready to use again.
*/
public void shutdown() {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
providerRepository.shutdown();
eventSupport.shutdown();
@ -375,7 +385,7 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
*/
@Override
public OpenFeatureAPI on(ProviderEvent event, Consumer<EventDetails> handler) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
this.eventSupport.addGlobalHandler(event, handler);
return this;
}
@ -386,18 +396,20 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
*/
@Override
public OpenFeatureAPI removeHandler(ProviderEvent event, Consumer<EventDetails> handler) {
this.eventSupport.removeGlobalHandler(event, handler);
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
this.eventSupport.removeGlobalHandler(event, handler);
}
return this;
}
void removeHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
eventSupport.removeClientHandler(domain, event, handler);
}
}
void addHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
// if the provider is in the state associated with event, run immediately
if (Optional.ofNullable(this.providerRepository.getProviderState(domain))
.orElse(ProviderState.READY)
@ -421,32 +433,28 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
* @param details the event details
*/
private void runHandlersForProvider(FeatureProvider provider, ProviderEvent event, ProviderEventDetails details) {
try (AutoCloseableLock __ = lock.readLockAutoCloseable()) {
try (AutoCloseableLock ignored = lock.readLockAutoCloseable()) {
List<String> domainsForProvider = providerRepository.getDomainsForProvider(provider);
final String providerName = Optional.ofNullable(provider.getMetadata())
.map(metadata -> metadata.getName())
.map(Metadata::getName)
.orElse(null);
// run the global handlers
eventSupport.runGlobalHandlers(event, EventDetails.fromProviderEventDetails(details, providerName));
// run the handlers associated with domains for this provider
domainsForProvider.forEach(domain -> {
eventSupport.runClientHandlers(
domain, event, EventDetails.fromProviderEventDetails(details, providerName, domain));
});
domainsForProvider.forEach(domain -> eventSupport.runClientHandlers(
domain, event, EventDetails.fromProviderEventDetails(details, providerName, domain)));
if (providerRepository.isDefaultProvider(provider)) {
// run handlers for clients that have no bound providers (since this is the default)
Set<String> allDomainNames = eventSupport.getAllDomainNames();
Set<String> boundDomains = providerRepository.getAllBoundDomains();
allDomainNames.removeAll(boundDomains);
allDomainNames.forEach(domain -> {
eventSupport.runClientHandlers(
domain, event, EventDetails.fromProviderEventDetails(details, providerName, domain));
});
allDomainNames.forEach(domain -> eventSupport.runClientHandlers(
domain, event, EventDetails.fromProviderEventDetails(details, providerName, domain)));
}
}
}

View File

@ -5,9 +5,8 @@ import dev.openfeature.sdk.exceptions.FatalError;
import dev.openfeature.sdk.exceptions.GeneralError;
import dev.openfeature.sdk.exceptions.OpenFeatureError;
import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
import dev.openfeature.sdk.internal.AutoCloseableLock;
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
import dev.openfeature.sdk.internal.ObjectUtils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -15,6 +14,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@ -46,11 +47,9 @@ public class OpenFeatureClient implements Client {
@Getter
private final String version;
private final List<Hook> clientHooks;
private final ConcurrentLinkedQueue<Hook> clientHooks;
private final HookSupport hookSupport;
AutoCloseableReentrantReadWriteLock hooksLock = new AutoCloseableReentrantReadWriteLock();
AutoCloseableReentrantReadWriteLock contextLock = new AutoCloseableReentrantReadWriteLock();
private EvaluationContext evaluationContext;
private final AtomicReference<EvaluationContext> evaluationContext = new AtomicReference<>();
/**
* Deprecated public constructor. Use OpenFeature.API.getClient() instead.
@ -68,7 +67,7 @@ public class OpenFeatureClient implements Client {
this.openfeatureApi = openFeatureAPI;
this.domain = domain;
this.version = version;
this.clientHooks = new ArrayList<>();
this.clientHooks = new ConcurrentLinkedQueue<>();
this.hookSupport = new HookSupport();
}
@ -125,9 +124,7 @@ public class OpenFeatureClient implements Client {
*/
@Override
public OpenFeatureClient addHooks(Hook... hooks) {
try (AutoCloseableLock __ = this.hooksLock.writeLockAutoCloseable()) {
this.clientHooks.addAll(Arrays.asList(hooks));
}
this.clientHooks.addAll(Arrays.asList(hooks));
return this;
}
@ -136,9 +133,7 @@ public class OpenFeatureClient implements Client {
*/
@Override
public List<Hook> getHooks() {
try (AutoCloseableLock __ = this.hooksLock.readLockAutoCloseable()) {
return this.clientHooks;
}
return new ArrayList<>(this.clientHooks);
}
/**
@ -146,9 +141,7 @@ public class OpenFeatureClient implements Client {
*/
@Override
public OpenFeatureClient setEvaluationContext(EvaluationContext evaluationContext) {
try (AutoCloseableLock __ = contextLock.writeLockAutoCloseable()) {
this.evaluationContext = evaluationContext;
}
this.evaluationContext.set(evaluationContext);
return this;
}
@ -157,32 +150,33 @@ public class OpenFeatureClient implements Client {
*/
@Override
public EvaluationContext getEvaluationContext() {
try (AutoCloseableLock __ = contextLock.readLockAutoCloseable()) {
return this.evaluationContext;
}
return this.evaluationContext.get();
}
@SuppressFBWarnings(
value = {"REC_CATCH_EXCEPTION"},
justification = "We don't want to allow any exception to reach the user. "
+ "Instead, we return an evaluation result with the appropriate error code.")
private <T> FlagEvaluationDetails<T> evaluateFlag(
FlagValueType type, String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
FlagEvaluationOptions flagOptions = ObjectUtils.defaultIfNull(
var flagOptions = ObjectUtils.defaultIfNull(
options, () -> FlagEvaluationOptions.builder().build());
Map<String, Object> hints = Collections.unmodifiableMap(flagOptions.getHookHints());
var hints = Collections.unmodifiableMap(flagOptions.getHookHints());
FlagEvaluationDetails<T> details = null;
List<Hook> mergedHooks = null;
HookContext<T> afterHookContext = null;
FeatureProvider provider;
try {
FeatureProviderStateManager stateManager = openfeatureApi.getFeatureProviderStateManager(this.domain);
var stateManager = openfeatureApi.getFeatureProviderStateManager(this.domain);
// provider must be accessed once to maintain a consistent reference
provider = stateManager.getProvider();
ProviderState state = stateManager.getState();
var provider = stateManager.getProvider();
var state = stateManager.getState();
mergedHooks = ObjectUtils.merge(
provider.getProviderHooks(), flagOptions.getHooks(), clientHooks, openfeatureApi.getHooks());
provider.getProviderHooks(), flagOptions.getHooks(), clientHooks, openfeatureApi.getMutableHooks());
EvaluationContext mergedCtx = hookSupport.beforeHooks(
var mergedCtx = hookSupport.beforeHooks(
type,
HookContext.from(
key,
@ -205,12 +199,12 @@ public class OpenFeatureClient implements Client {
throw new FatalError("Provider is in an irrecoverable error state");
}
ProviderEvaluation<T> providerEval =
var providerEval =
(ProviderEvaluation<T>) createProviderEvaluation(type, key, defaultValue, provider, mergedCtx);
details = FlagEvaluationDetails.from(providerEval, key);
if (details.getErrorCode() != null) {
OpenFeatureError error =
var error =
ExceptionUtils.instantiateErrorByErrorCode(details.getErrorCode(), details.getErrorMessage());
enrichDetailsWithErrorDefaults(defaultValue, details);
hookSupport.errorHooks(type, afterHookContext, error, mergedHooks, hints);
@ -264,7 +258,7 @@ public class OpenFeatureClient implements Client {
*/
private EvaluationContext mergeEvaluationContext(EvaluationContext invocationContext) {
final EvaluationContext apiContext = openfeatureApi.getEvaluationContext();
final EvaluationContext clientContext = this.getEvaluationContext();
final EvaluationContext clientContext = evaluationContext.get();
final EvaluationContext transactionContext = openfeatureApi.getTransactionContext();
return mergeContextMaps(apiContext, transactionContext, clientContext, invocationContext);
}

View File

@ -0,0 +1,95 @@
package dev.openfeature.sdk;
/**
* The Telemetry class provides constants and methods for creating OpenTelemetry compliant
* evaluation events.
*/
public class Telemetry {
private Telemetry() {}
/*
The OpenTelemetry compliant event attributes for flag evaluation.
Specification: https://opentelemetry.io/docs/specs/semconv/feature-flags/feature-flags-logs/
*/
public static final String TELEMETRY_KEY = "feature_flag.key";
public static final String TELEMETRY_ERROR_CODE = "error.type";
public static final String TELEMETRY_VARIANT = "feature_flag.result.variant";
public static final String TELEMETRY_VALUE = "feature_flag.result.value";
public static final String TELEMETRY_CONTEXT_ID = "feature_flag.context.id";
public static final String TELEMETRY_ERROR_MSG = "feature_flag.evaluation.error.message";
public static final String TELEMETRY_REASON = "feature_flag.result.reason";
public static final String TELEMETRY_PROVIDER = "feature_flag.provider.name";
public static final String TELEMETRY_FLAG_SET_ID = "feature_flag.set.id";
public static final String TELEMETRY_VERSION = "feature_flag.version";
// Well-known flag metadata attributes for telemetry events.
// Specification: https://openfeature.dev/specification/appendix-d#flag-metadata
public static final String TELEMETRY_FLAG_META_CONTEXT_ID = "contextId";
public static final String TELEMETRY_FLAG_META_FLAG_SET_ID = "flagSetId";
public static final String TELEMETRY_FLAG_META_VERSION = "version";
public static final String FLAG_EVALUATION_EVENT_NAME = "feature_flag.evaluation";
/**
* Creates an EvaluationEvent using the provided HookContext and ProviderEvaluation.
*
* @param hookContext the context containing flag evaluation details
* @param evaluationDetails the evaluation result from the provider
*
* @return an EvaluationEvent populated with telemetry data
*/
public static EvaluationEvent createEvaluationEvent(
HookContext<?> hookContext, FlagEvaluationDetails<?> evaluationDetails) {
EvaluationEvent.EvaluationEventBuilder evaluationEventBuilder = EvaluationEvent.builder()
.name(FLAG_EVALUATION_EVENT_NAME)
.attribute(TELEMETRY_KEY, hookContext.getFlagKey())
.attribute(TELEMETRY_PROVIDER, hookContext.getProviderMetadata().getName());
if (evaluationDetails.getReason() != null) {
evaluationEventBuilder.attribute(
TELEMETRY_REASON, evaluationDetails.getReason().toLowerCase());
} else {
evaluationEventBuilder.attribute(
TELEMETRY_REASON, Reason.UNKNOWN.name().toLowerCase());
}
if (evaluationDetails.getVariant() != null) {
evaluationEventBuilder.attribute(TELEMETRY_VARIANT, evaluationDetails.getVariant());
} else {
evaluationEventBuilder.attribute(TELEMETRY_VALUE, evaluationDetails.getValue());
}
String contextId = evaluationDetails.getFlagMetadata().getString(TELEMETRY_FLAG_META_CONTEXT_ID);
if (contextId != null) {
evaluationEventBuilder.attribute(TELEMETRY_CONTEXT_ID, contextId);
} else {
evaluationEventBuilder.attribute(
TELEMETRY_CONTEXT_ID, hookContext.getCtx().getTargetingKey());
}
String setID = evaluationDetails.getFlagMetadata().getString(TELEMETRY_FLAG_META_FLAG_SET_ID);
if (setID != null) {
evaluationEventBuilder.attribute(TELEMETRY_FLAG_SET_ID, setID);
}
String version = evaluationDetails.getFlagMetadata().getString(TELEMETRY_FLAG_META_VERSION);
if (version != null) {
evaluationEventBuilder.attribute(TELEMETRY_VERSION, version);
}
if (Reason.ERROR.name().equals(evaluationDetails.getReason())) {
if (evaluationDetails.getErrorCode() != null) {
evaluationEventBuilder.attribute(TELEMETRY_ERROR_CODE, evaluationDetails.getErrorCode());
} else {
evaluationEventBuilder.attribute(TELEMETRY_ERROR_CODE, ErrorCode.GENERAL);
}
if (evaluationDetails.getErrorMessage() != null) {
evaluationEventBuilder.attribute(TELEMETRY_ERROR_MSG, evaluationDetails.getErrorMessage());
}
}
return evaluationEventBuilder.build();
}
}

View File

@ -5,6 +5,7 @@ package dev.openfeature.sdk;
* for the duration of a single transaction.
* Examples of potential transaction specific context include: a user id, user agent, IP.
* Transaction context is merged with evaluation context prior to flag evaluation.
*
* <p>
* The precedence of merging context can be seen in
* <a href=https://openfeature.dev/specification/sections/evaluation-context#requirement-323>the specification</a>.

View File

@ -1,6 +1,7 @@
package dev.openfeature.sdk.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
@ -64,9 +65,9 @@ public class ObjectUtils {
* @return resulting object
*/
@SafeVarargs
public static <T> List<T> merge(List<T>... sources) {
public static <T> List<T> merge(Collection<T>... sources) {
List<T> merged = new ArrayList<>();
for (List<T> source : sources) {
for (Collection<T> source : sources) {
merged.addAll(source);
}
return merged;

View File

@ -0,0 +1,75 @@
package dev.openfeature.sdk;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
@Timeout(value = 5, threadMode = Timeout.ThreadMode.SEPARATE_THREAD)
class AwaitableTest {
@Test
void waitingForFinishedIsANoOp() {
var startTime = System.currentTimeMillis();
Awaitable.FINISHED.await();
var endTime = System.currentTimeMillis();
assertTrue(endTime - startTime < 10);
}
@Test
void waitingForNotFinishedWaitsEvenWhenInterrupted() throws InterruptedException {
var awaitable = new Awaitable();
var mayProceed = new AtomicBoolean(false);
var thread = new Thread(() -> {
awaitable.await();
if (!mayProceed.get()) {
fail();
}
});
thread.start();
var startTime = System.currentTimeMillis();
do {
thread.interrupt();
} while (startTime + 1000 > System.currentTimeMillis());
mayProceed.set(true);
awaitable.wakeup();
thread.join();
}
@Test
void callingWakeUpWakesUpAllWaitingThreads() throws InterruptedException {
var awaitable = new Awaitable();
var isRunning = new AtomicInteger();
Runnable runnable = () -> {
isRunning.incrementAndGet();
var start = System.currentTimeMillis();
awaitable.await();
var end = System.currentTimeMillis();
if (end - start > 10) {
fail();
}
};
var numThreads = 2;
var threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++) {
threads[i] = new Thread(runnable);
threads[i].start();
}
await().atMost(1, TimeUnit.SECONDS).until(() -> isRunning.get() == numThreads);
awaitable.wakeup();
for (int i = 0; i < numThreads; i++) {
threads[i].join();
}
}
}

View File

@ -150,7 +150,7 @@ class DeveloperExperienceTest implements HookFixtures {
api.setProviderAndWait(domain, provider);
Client client = api.getClient(domain);
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
provider.emitProviderError(ProviderEventDetails.builder().build());
provider.emitProviderError(ProviderEventDetails.builder().build()).await();
assertThat(client.getProviderState()).isEqualTo(ProviderState.ERROR);
}
@ -165,7 +165,7 @@ class DeveloperExperienceTest implements HookFixtures {
api.setProviderAndWait(domain, provider);
Client client = api.getClient(domain);
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
provider.emitProviderStale(ProviderEventDetails.builder().build());
provider.emitProviderStale(ProviderEventDetails.builder().build()).await();
assertThat(client.getProviderState()).isEqualTo(ProviderState.STALE);
}
@ -180,9 +180,9 @@ class DeveloperExperienceTest implements HookFixtures {
api.setProviderAndWait(domain, provider);
Client client = api.getClient(domain);
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
provider.emitProviderStale(ProviderEventDetails.builder().build());
provider.emitProviderStale(ProviderEventDetails.builder().build()).await();
assertThat(client.getProviderState()).isEqualTo(ProviderState.STALE);
provider.emitProviderReady(ProviderEventDetails.builder().build());
provider.emitProviderReady(ProviderEventDetails.builder().build()).await();
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
}
}

View File

@ -32,6 +32,7 @@ class EventProviderTest {
}
@Test
@Timeout(value = 2, threadMode = Timeout.ThreadMode.SEPARATE_THREAD)
@DisplayName("should run attached onEmit with emitters")
void emitsEventsWhenAttached() {
TriConsumer<EventProvider, ProviderEvent, ProviderEventDetails> onEmit = mockOnEmit();

View File

@ -24,7 +24,7 @@ class EventsTest {
private OpenFeatureAPI api;
@BeforeEach
public void setUp() throws Exception {
void setUp() {
api = new OpenFeatureAPI();
}
@ -578,7 +578,7 @@ class EventsTest {
number = "5.3.3",
text = "Handlers attached after the provider is already in the associated state, MUST run immediately.")
void matchingReadyEventsMustRunImmediately() {
final String name = "matchingEventsMustRunImmediately";
final String name = "matchingReadyEventsMustRunImmediately";
final Consumer<EventDetails> handler = mockHandler();
// provider which is already ready
@ -597,14 +597,14 @@ class EventsTest {
number = "5.3.3",
text = "Handlers attached after the provider is already in the associated state, MUST run immediately.")
void matchingStaleEventsMustRunImmediately() {
final String name = "matchingEventsMustRunImmediately";
final String name = "matchingStaleEventsMustRunImmediately";
final Consumer<EventDetails> handler = mockHandler();
// provider which is already stale
TestEventsProvider provider = new TestEventsProvider(INIT_DELAY);
Client client = api.getClient(name);
api.setProviderAndWait(name, provider);
provider.emitProviderStale(ProviderEventDetails.builder().build());
provider.emitProviderStale(ProviderEventDetails.builder().build()).await();
assertThat(client.getProviderState()).isEqualTo(ProviderState.STALE);
// should run even though handler was added after stale
@ -618,14 +618,14 @@ class EventsTest {
number = "5.3.3",
text = "Handlers attached after the provider is already in the associated state, MUST run immediately.")
void matchingErrorEventsMustRunImmediately() {
final String name = "matchingEventsMustRunImmediately";
final String name = "matchingErrorEventsMustRunImmediately";
final Consumer<EventDetails> handler = mockHandler();
// provider which is already in error
TestEventsProvider provider = new TestEventsProvider(INIT_DELAY);
Client client = api.getClient(name);
api.setProviderAndWait(name, provider);
provider.emitProviderError(ProviderEventDetails.builder().build());
provider.emitProviderError(ProviderEventDetails.builder().build()).await();
assertThat(client.getProviderState()).isEqualTo(ProviderState.ERROR);
verify(handler, never()).accept(any());

View File

@ -20,7 +20,6 @@ class LockingSingeltonTest {
private static OpenFeatureAPI api;
private OpenFeatureClient client;
private AutoCloseableReentrantReadWriteLock apiLock;
private AutoCloseableReentrantReadWriteLock clientContextLock;
private AutoCloseableReentrantReadWriteLock clientHooksLock;
@BeforeAll
@ -36,10 +35,7 @@ class LockingSingeltonTest {
apiLock = setupLock(apiLock, mockInnerReadLock(), mockInnerWriteLock());
OpenFeatureAPI.lock = apiLock;
clientContextLock = setupLock(clientContextLock, mockInnerReadLock(), mockInnerWriteLock());
clientHooksLock = setupLock(clientHooksLock, mockInnerReadLock(), mockInnerWriteLock());
client.contextLock = clientContextLock;
client.hooksLock = clientHooksLock;
}
@Nested
@ -137,50 +133,6 @@ class LockingSingeltonTest {
}
}
@Test
void addHooksShouldWriteLockAndUnlock() {
client.addHooks(new Hook() {});
verify(clientHooksLock.writeLock()).lock();
verify(clientHooksLock.writeLock()).unlock();
api.addHooks(new Hook() {});
verify(apiLock.writeLock()).lock();
verify(apiLock.writeLock()).unlock();
}
@Test
void getHooksShouldReadLockAndUnlock() {
client.getHooks();
verify(clientHooksLock.readLock()).lock();
verify(clientHooksLock.readLock()).unlock();
api.getHooks();
verify(apiLock.readLock()).lock();
verify(apiLock.readLock()).unlock();
}
@Test
void setContextShouldWriteLockAndUnlock() {
client.setEvaluationContext(new ImmutableContext());
verify(clientContextLock.writeLock()).lock();
verify(clientContextLock.writeLock()).unlock();
api.setEvaluationContext(new ImmutableContext());
verify(apiLock.writeLock()).lock();
verify(apiLock.writeLock()).unlock();
}
@Test
void getContextShouldReadLockAndUnlock() {
client.getEvaluationContext();
verify(clientContextLock.readLock()).lock();
verify(clientContextLock.readLock()).unlock();
api.getEvaluationContext();
verify(apiLock.readLock()).lock();
verify(apiLock.readLock()).unlock();
}
@Test
void setTransactionalContextPropagatorShouldWriteLockAndUnlock() {
api.setTransactionContextPropagator(new NoOpTransactionContextPropagator());
@ -195,13 +147,6 @@ class LockingSingeltonTest {
verify(apiLock.readLock()).unlock();
}
@Test
void clearHooksShouldWriteLockAndUnlock() {
api.clearHooks();
verify(apiLock.writeLock()).lock();
verify(apiLock.writeLock()).unlock();
}
private static ReentrantReadWriteLock.ReadLock mockInnerReadLock() {
ReentrantReadWriteLock.ReadLock readLockMock = mock(ReentrantReadWriteLock.ReadLock.class);
doNothing().when(readLockMock).lock();

View File

@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import dev.openfeature.sdk.providers.memory.InMemoryProvider;
@ -112,7 +113,7 @@ class OpenFeatureAPITest {
api.getClient().track("track-event", new ImmutableContext(), new MutableTrackingEventDetails(22.2f));
verify(featureProvider).initialize(any());
verify(featureProvider).getMetadata();
verify(featureProvider, times(2)).getMetadata();
verify(featureProvider).track(any(), any(), any());
}
}

View File

@ -0,0 +1,231 @@
package dev.openfeature.sdk;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
public class TelemetryTest {
@Test
void testCreatesEvaluationEventWithMandatoryFields() {
// Arrange
String flagKey = "test-flag";
String providerName = "test-provider";
String reason = "static";
Metadata providerMetadata = mock(Metadata.class);
when(providerMetadata.getName()).thenReturn(providerName);
HookContext<Boolean> hookContext = HookContext.<Boolean>builder()
.flagKey(flagKey)
.providerMetadata(providerMetadata)
.type(FlagValueType.BOOLEAN)
.defaultValue(false)
.ctx(new ImmutableContext())
.build();
FlagEvaluationDetails<Boolean> evaluation = FlagEvaluationDetails.<Boolean>builder()
.reason(reason)
.value(true)
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, evaluation);
assertEquals(Telemetry.FLAG_EVALUATION_EVENT_NAME, event.getName());
assertEquals(flagKey, event.getAttributes().get(Telemetry.TELEMETRY_KEY));
assertEquals(providerName, event.getAttributes().get(Telemetry.TELEMETRY_PROVIDER));
assertEquals(reason.toLowerCase(), event.getAttributes().get(Telemetry.TELEMETRY_REASON));
}
@Test
void testHandlesNullReason() {
// Arrange
String flagKey = "test-flag";
String providerName = "test-provider";
Metadata providerMetadata = mock(Metadata.class);
when(providerMetadata.getName()).thenReturn(providerName);
HookContext<Boolean> hookContext = HookContext.<Boolean>builder()
.flagKey(flagKey)
.providerMetadata(providerMetadata)
.type(FlagValueType.BOOLEAN)
.defaultValue(false)
.ctx(new ImmutableContext())
.build();
FlagEvaluationDetails<Boolean> evaluation = FlagEvaluationDetails.<Boolean>builder()
.reason(null)
.value(true)
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, evaluation);
assertEquals(Reason.UNKNOWN.name().toLowerCase(), event.getAttributes().get(Telemetry.TELEMETRY_REASON));
}
@Test
void testSetsVariantAttributeWhenVariantExists() {
HookContext<String> hookContext = HookContext.<String>builder()
.flagKey("testFlag")
.type(FlagValueType.STRING)
.defaultValue("default")
.ctx(mock(EvaluationContext.class))
.clientMetadata(mock(ClientMetadata.class))
.providerMetadata(mock(Metadata.class))
.build();
FlagEvaluationDetails<String> providerEvaluation = FlagEvaluationDetails.<String>builder()
.variant("testVariant")
.flagMetadata(ImmutableMetadata.builder().build())
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, providerEvaluation);
assertEquals("testVariant", event.getAttributes().get(Telemetry.TELEMETRY_VARIANT));
}
@Test
void test_sets_value_in_body_when_variant_is_null() {
HookContext<String> hookContext = HookContext.<String>builder()
.flagKey("testFlag")
.type(FlagValueType.STRING)
.defaultValue("default")
.ctx(mock(EvaluationContext.class))
.clientMetadata(mock(ClientMetadata.class))
.providerMetadata(mock(Metadata.class))
.build();
FlagEvaluationDetails<String> providerEvaluation = FlagEvaluationDetails.<String>builder()
.value("testValue")
.flagMetadata(ImmutableMetadata.builder().build())
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, providerEvaluation);
assertEquals("testValue", event.getAttributes().get(Telemetry.TELEMETRY_VALUE));
}
@Test
void testAllFieldsPopulated() {
EvaluationContext evaluationContext = mock(EvaluationContext.class);
when(evaluationContext.getTargetingKey()).thenReturn("realTargetingKey");
Metadata providerMetadata = mock(Metadata.class);
when(providerMetadata.getName()).thenReturn("realProviderName");
HookContext<String> hookContext = HookContext.<String>builder()
.flagKey("realFlag")
.type(FlagValueType.STRING)
.defaultValue("realDefault")
.ctx(evaluationContext)
.clientMetadata(mock(ClientMetadata.class))
.providerMetadata(providerMetadata)
.build();
FlagEvaluationDetails<String> providerEvaluation = FlagEvaluationDetails.<String>builder()
.flagMetadata(ImmutableMetadata.builder()
.addString("contextId", "realContextId")
.addString("flagSetId", "realFlagSetId")
.addString("version", "realVersion")
.build())
.reason(Reason.DEFAULT.name())
.variant("realVariant")
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, providerEvaluation);
assertEquals("realFlag", event.getAttributes().get(Telemetry.TELEMETRY_KEY));
assertEquals("realProviderName", event.getAttributes().get(Telemetry.TELEMETRY_PROVIDER));
assertEquals("default", event.getAttributes().get(Telemetry.TELEMETRY_REASON));
assertEquals("realContextId", event.getAttributes().get(Telemetry.TELEMETRY_CONTEXT_ID));
assertEquals("realFlagSetId", event.getAttributes().get(Telemetry.TELEMETRY_FLAG_SET_ID));
assertEquals("realVersion", event.getAttributes().get(Telemetry.TELEMETRY_VERSION));
assertNull(event.getAttributes().get(Telemetry.TELEMETRY_ERROR_CODE));
assertEquals("realVariant", event.getAttributes().get(Telemetry.TELEMETRY_VARIANT));
}
@Test
void testErrorEvaluation() {
EvaluationContext evaluationContext = mock(EvaluationContext.class);
when(evaluationContext.getTargetingKey()).thenReturn("realTargetingKey");
Metadata providerMetadata = mock(Metadata.class);
when(providerMetadata.getName()).thenReturn("realProviderName");
HookContext<String> hookContext = HookContext.<String>builder()
.flagKey("realFlag")
.type(FlagValueType.STRING)
.defaultValue("realDefault")
.ctx(evaluationContext)
.clientMetadata(mock(ClientMetadata.class))
.providerMetadata(providerMetadata)
.build();
FlagEvaluationDetails<String> providerEvaluation = FlagEvaluationDetails.<String>builder()
.flagMetadata(ImmutableMetadata.builder()
.addString("contextId", "realContextId")
.addString("flagSetId", "realFlagSetId")
.addString("version", "realVersion")
.build())
.reason(Reason.ERROR.name())
.errorMessage("realErrorMessage")
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, providerEvaluation);
assertEquals("realFlag", event.getAttributes().get(Telemetry.TELEMETRY_KEY));
assertEquals("realProviderName", event.getAttributes().get(Telemetry.TELEMETRY_PROVIDER));
assertEquals("error", event.getAttributes().get(Telemetry.TELEMETRY_REASON));
assertEquals("realContextId", event.getAttributes().get(Telemetry.TELEMETRY_CONTEXT_ID));
assertEquals("realFlagSetId", event.getAttributes().get(Telemetry.TELEMETRY_FLAG_SET_ID));
assertEquals("realVersion", event.getAttributes().get(Telemetry.TELEMETRY_VERSION));
assertEquals(ErrorCode.GENERAL, event.getAttributes().get(Telemetry.TELEMETRY_ERROR_CODE));
assertEquals("realErrorMessage", event.getAttributes().get(Telemetry.TELEMETRY_ERROR_MSG));
assertNull(event.getAttributes().get(Telemetry.TELEMETRY_VARIANT));
}
@Test
void testErrorCodeEvaluation() {
EvaluationContext evaluationContext = mock(EvaluationContext.class);
when(evaluationContext.getTargetingKey()).thenReturn("realTargetingKey");
Metadata providerMetadata = mock(Metadata.class);
when(providerMetadata.getName()).thenReturn("realProviderName");
HookContext<String> hookContext = HookContext.<String>builder()
.flagKey("realFlag")
.type(FlagValueType.STRING)
.defaultValue("realDefault")
.ctx(evaluationContext)
.clientMetadata(mock(ClientMetadata.class))
.providerMetadata(providerMetadata)
.build();
FlagEvaluationDetails<String> providerEvaluation = FlagEvaluationDetails.<String>builder()
.flagMetadata(ImmutableMetadata.builder()
.addString("contextId", "realContextId")
.addString("flagSetId", "realFlagSetId")
.addString("version", "realVersion")
.build())
.reason(Reason.ERROR.name())
.errorMessage("realErrorMessage")
.errorCode(ErrorCode.INVALID_CONTEXT)
.build();
EvaluationEvent event = Telemetry.createEvaluationEvent(hookContext, providerEvaluation);
assertEquals("realFlag", event.getAttributes().get(Telemetry.TELEMETRY_KEY));
assertEquals("realProviderName", event.getAttributes().get(Telemetry.TELEMETRY_PROVIDER));
assertEquals("error", event.getAttributes().get(Telemetry.TELEMETRY_REASON));
assertEquals("realContextId", event.getAttributes().get(Telemetry.TELEMETRY_CONTEXT_ID));
assertEquals("realFlagSetId", event.getAttributes().get(Telemetry.TELEMETRY_FLAG_SET_ID));
assertEquals("realVersion", event.getAttributes().get(Telemetry.TELEMETRY_VERSION));
assertEquals(ErrorCode.INVALID_CONTEXT, event.getAttributes().get(Telemetry.TELEMETRY_ERROR_CODE));
assertEquals("realErrorMessage", event.getAttributes().get(Telemetry.TELEMETRY_ERROR_MSG));
assertNull(event.getAttributes().get(Telemetry.TELEMETRY_VARIANT));
}
}

View File

@ -3,9 +3,14 @@ package dev.openfeature.sdk.providers.memory;
import static dev.openfeature.sdk.Structure.mapToStructure;
import static dev.openfeature.sdk.testutils.TestFlagsUtils.buildFlags;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import com.google.common.collect.ImmutableMap;
import dev.openfeature.sdk.Client;
@ -19,6 +24,7 @@ import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
import dev.openfeature.sdk.exceptions.TypeMismatchError;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeEach;
@ -34,10 +40,11 @@ class InMemoryProviderTest {
@SneakyThrows
@BeforeEach
void beforeEach() {
final var configChangedEventCounter = new AtomicInteger();
Map<String, Flag<?>> flags = buildFlags();
provider = spy(new InMemoryProvider(flags));
api = OpenFeatureAPITestUtil.createAPI();
api.onProviderConfigurationChanged(eventDetails -> {});
api.onProviderConfigurationChanged(eventDetails -> configChangedEventCounter.incrementAndGet());
api.setProviderAndWait(provider);
client = api.getClient();
provider.updateFlags(flags);
@ -48,6 +55,11 @@ class InMemoryProviderTest {
.variant("off", false)
.defaultVariant("on")
.build());
// wait for the two config changed events to be fired, otherwise they could mess with our tests
while (configChangedEventCounter.get() < 2) {
Thread.sleep(1);
}
}
@Test

View File

@ -1 +1 @@
1.14.2
1.16.0