Compare commits
564 Commits
Author | SHA1 | Date |
---|---|---|
|
ac3344c7f6 | |
|
ecc8f7e3ad | |
|
cbf7a58622 | |
|
1382b367d9 | |
|
5b3e3656f6 | |
|
1d3fab6184 | |
|
006ae75e2b | |
|
aa0569379b | |
|
bf68cbdedf | |
|
62738f7f16 | |
|
1e8f5c880c | |
|
488196656a | |
|
26716a51cf | |
|
908755c2c2 | |
|
d2b1dc3a41 | |
|
85d89ee79a | |
|
6194186b3e | |
|
5425a34a12 | |
|
957c0d1ba3 | |
|
ebea0fdf1c | |
|
08f549afd1 | |
|
a5d1cbced4 | |
|
0fd9d3dcfb | |
|
0515ad54c4 | |
|
69519b1ef7 | |
|
2e3b479cb1 | |
|
49214b7282 | |
|
fc430c3e1d | |
|
86a5916f0d | |
|
34b22e8d93 | |
|
300a705e0a | |
|
b64efe82d9 | |
|
6f67b06f71 | |
|
e67f598357 | |
|
312b6df5d2 | |
|
8fad544b17 | |
|
c3eaecdb8b | |
|
7c2af57a36 | |
|
8bf777a7e9 | |
|
936ff60fac | |
|
99a3006de8 | |
|
8e51e6fe10 | |
|
844d5e244b | |
|
0b57bcafc1 | |
|
3dd7d5d426 | |
|
6cca721be5 | |
|
4481537ceb | |
|
b5d873e44d | |
|
545d6aac09 | |
|
2dcd6a1dd0 | |
|
3ed65cfb0c | |
|
6597de7a98 | |
|
376f81f5c3 | |
|
1558a86249 | |
|
f8260a1c3a | |
|
50a6b168a7 | |
|
b6ceff2ecb | |
|
2de7616676 | |
|
f10aaaa357 | |
|
40b319c5de | |
|
5e922cf3ef | |
|
6a95c008e9 | |
|
dcbfd265a3 | |
|
e17b0b2975 | |
|
b45a937017 | |
|
36eed065e7 | |
|
e3379395e6 | |
|
b667aa3251 | |
|
1714efe81a | |
|
d9a72d2aaf | |
|
cfd9512728 | |
|
f6bd30db93 | |
|
e2813b2e5d | |
|
bc10bacb5a | |
|
7182a7fc41 | |
|
d0ae548277 | |
|
e568f3a4f5 | |
|
58454b4eaa | |
|
78657ee79e | |
|
3403510515 | |
|
4dc988b637 | |
|
f2348ea370 | |
|
85b200a08b | |
|
f965cbcb37 | |
|
b09e88798f | |
|
7e74f2aa3a | |
|
62ba6db457 | |
|
96cf9c7f54 | |
|
99faaf88aa | |
|
1cc851b293 | |
|
32137bfa82 | |
|
45ec4b1b77 | |
|
014f8a59da | |
|
1c4d2efafd | |
|
844374a42b | |
|
a7828e73a8 | |
|
6b6849f3a3 | |
|
495da271be | |
|
e19ccaa35d | |
|
498fd38265 | |
|
a3e2a59aeb | |
|
665dd51eb2 | |
|
a6389e89f6 | |
|
97b442ed6e | |
|
0c77c84460 | |
|
4607c62f15 | |
|
a5789038ac | |
|
e066d3f749 | |
|
5b327eeb77 | |
|
e25181982a | |
|
3c69f2f36c | |
|
345cdcfa10 | |
|
ca160cab7c | |
|
e211397d51 | |
|
5b2f1513ab | |
|
f834e11acc | |
|
ef32f11571 | |
|
07301bda3f | |
|
384953d30e | |
|
1f2d071508 | |
|
d6ebc161a9 | |
|
1fcf0e77d9 | |
|
37d76be697 | |
|
d7b591c9f9 | |
|
7f54c334da | |
|
24ef9dd290 | |
|
753667925a | |
|
87c06d9edd | |
|
85fd5e0997 | |
|
d8f6514598 | |
|
cb574d93b6 | |
|
4125ae8380 | |
|
387e5f2e3b | |
|
b6becac2c4 | |
|
922e17e677 | |
|
d61c33e466 | |
|
2239f054b9 | |
|
8359ef13bb | |
|
dbf92df33b | |
|
706565581d | |
|
9750f75d04 | |
|
de3e213ac8 | |
|
6b65e26c74 | |
|
d233480912 | |
|
69b571eda7 | |
|
f8df5fb84a | |
|
d54c68a8e9 | |
|
c550d59722 | |
|
d00e4b5b24 | |
|
c37d249776 | |
|
959e675e4c | |
|
67b34f84a3 | |
|
30b6d004aa | |
|
ecea9df932 | |
|
6c03e5d84a | |
|
31444d6c8f | |
|
dd83114c4d | |
|
2a1adca8c2 | |
|
59017977a4 | |
|
989f4ae542 | |
|
b133c2fa52 | |
|
7df9565691 | |
|
2ec7c6c7ff | |
|
698756856b | |
|
5de33c02a6 | |
|
de64eddfb3 | |
|
d95e270653 | |
|
1504d0f798 | |
|
88a778cc03 | |
|
50b45b2be4 | |
|
dd9227a924 | |
|
cdcdc143ea | |
|
3920c638a4 | |
|
4e535fd10f | |
|
4817864fd7 | |
|
90217b2083 | |
|
88baa65dd0 | |
|
e163ce1c06 | |
|
5436eb0d5d | |
|
859a36cbfa | |
|
9e782308d3 | |
|
4ba5695eee | |
|
9ab26182ea | |
|
c33ac2d9b2 | |
|
08c38fb553 | |
|
3baf0df966 | |
|
69cdc772a6 | |
|
8f3ced5907 | |
|
538140dfe7 | |
|
b7978832b7 | |
|
26e1d7fff3 | |
|
46903c6f27 | |
|
37ed6a424c | |
|
208411e723 | |
|
9a1e9abd64 | |
|
40fa173338 | |
|
cda34053f7 | |
|
99d818572a | |
|
6f36434c52 | |
|
ba9cc4b85a | |
|
7916d76635 | |
|
6874de64ce | |
|
f9fa54be49 | |
|
78adc77c23 | |
|
f7f6586d72 | |
|
34919561b7 | |
|
531fc385b6 | |
|
305e0329e7 | |
|
874e86df5c | |
|
122e82f843 | |
|
5671184e7f | |
|
6071932cb4 | |
|
0af9f2901f | |
|
a5eb21d1a2 | |
|
6c4205a008 | |
|
0b5b423bdd | |
|
882d2dd5bd | |
|
c69d3a4bd1 | |
|
640e35e853 | |
|
32a39335de | |
|
45b3995bda | |
|
b390d5f0b0 | |
|
8a1ab7ea18 | |
|
a3854d6ab1 | |
|
b997946db1 | |
|
c2a82dbdba | |
|
9274c117ab | |
|
9c92ebb1bd | |
|
d825ff8363 | |
|
ae85278c30 | |
|
3c97b7baaf | |
|
4086dea703 | |
|
a1c558f4ff | |
|
2e10d34920 | |
|
20bbb2337c | |
|
64ec68bcf5 | |
|
f1817d8fef | |
|
fc6f35e581 | |
|
c62ade3878 | |
|
6d60c962fb | |
|
992c00396c | |
|
d274cdac37 | |
|
6a7987455e | |
|
f39c4b5af5 | |
|
482a5aef10 | |
|
834f720718 | |
|
6772d3f394 | |
|
6d169f55e2 | |
|
4440cda6a5 | |
|
86e18c5d28 | |
|
9acc8612a5 | |
|
fd1c1702c6 | |
|
884f8fbf77 | |
|
b0abfd02cf | |
|
cacacc2615 | |
|
c87c6e7a76 | |
|
baaa78b7ec | |
|
64ad644bdb | |
|
c5ad1b4d4f | |
|
da725d89e0 | |
|
473be8659c | |
|
409fd042f3 | |
|
bb3272d364 | |
|
5b460ead7e | |
|
b3549a1b4a | |
|
4bbaf51753 | |
|
764d6650e6 | |
|
a0723ec2f8 | |
|
234062cf33 | |
|
13811dcf25 | |
|
3227623425 | |
|
19ed5c7c97 | |
|
e91194ae16 | |
|
bbc934c6d9 | |
|
37f0f06467 | |
|
45d0656520 | |
|
9cadc71d9d | |
|
1b4947f108 | |
|
7aa77b8614 | |
|
6d3bb69420 | |
|
273efc62a7 | |
|
9f37927eaa | |
|
92c87913ac | |
|
d5228f5ccf | |
|
1df54411b7 | |
|
a94bd37cff | |
|
1c21d2444b | |
|
a3ced47e5d | |
|
21dbd3fc4c | |
|
446e2987e9 | |
|
eb4f625561 | |
|
3a9fd60fd4 | |
|
2bb2ed3992 | |
|
d959059177 | |
|
d2cb092b09 | |
|
a2a57ab8f1 | |
|
08da9a3439 | |
|
e32a712615 | |
|
54a234519f | |
|
30eb2ce082 | |
|
309f28b520 | |
|
2dba3a737d | |
|
8621944633 | |
|
f99de6fa55 | |
|
f3163dfbd4 | |
|
d5082cd5f6 | |
|
89c7f85da4 | |
|
5c7c28706e | |
|
4e3a329c40 | |
|
d0309eaa66 | |
|
f1cee1ca4c | |
|
fd7659a46f | |
|
7a1eb9b9e9 | |
|
74958fd261 | |
|
0009e23c7b | |
|
36620f8408 | |
|
0db0a50cf4 | |
|
a08589664c | |
|
cedad9c2c6 | |
|
9fb469f8e8 | |
|
c8c70e23e8 | |
|
b08e8d5537 | |
|
59139a2186 | |
|
a432760fc9 | |
|
02eed7a32c | |
|
d6d284b6a3 | |
|
3f1cfed913 | |
|
51a3410d8e | |
|
432ec438ef | |
|
2d3be2617b | |
|
4e39b55bda | |
|
473a05784c | |
|
457da96e7b | |
|
8037e343bd | |
|
90088188c9 | |
|
b144763299 | |
|
f28cefe3b1 | |
|
a8813760d6 | |
|
98a7ed0727 | |
|
20e3a5d3fe | |
|
82a5eb5687 | |
|
4f32abaf84 | |
|
7ccc896665 | |
|
e982216f70 | |
|
fdda5e94b6 | |
|
6d38b2c5a9 | |
|
03e6604960 | |
|
16ec4e459b | |
|
aaab1598a1 | |
|
2489e40c29 | |
|
0c0c5f4ad9 | |
|
20ea6bd99d | |
|
9eb64a7471 | |
|
a0041c10e4 | |
|
e6573838a0 | |
|
1f2c5a1b2a | |
|
43f076a125 | |
|
0c8ff472f2 | |
|
16e1dec928 | |
|
26659a3eed | |
|
626f5e17c0 | |
|
d4dac274ee | |
|
c8722a2ac6 | |
|
f7d6202e13 | |
|
02f4ec1061 | |
|
4f83d61306 | |
|
3816151b87 | |
|
91fffb3560 | |
|
93f4feb818 | |
|
8765cf3440 | |
|
58635411bd | |
|
f2c37eacc2 | |
|
db1bc75cde | |
|
2393924592 | |
|
c5bace6ff2 | |
|
b919333823 | |
|
90c65666e2 | |
|
ce06eee9df | |
|
5d9780333a | |
|
a2a55e8f31 | |
|
48f0685051 | |
|
1b1e527e78 | |
|
dd8ba81f12 | |
|
52e6d2b0ee | |
|
0f94ba890e | |
|
2412f296b5 | |
|
17a58efc7e | |
|
244f216582 | |
|
37b56ac2da | |
|
ce19ac91f6 | |
|
9d69ebd94a | |
|
7cb89087da | |
|
6fc0b90610 | |
|
29901b87ea | |
|
d1478c001a | |
|
b80fd6d307 | |
|
c68f78e17b | |
|
caec6e35e9 | |
|
64082617fa | |
|
082f5746c8 | |
|
d60593fa11 | |
|
870fc27ed7 | |
|
58ead7fa91 | |
|
9f6a40ec9b | |
|
7e0c70f7c5 | |
|
1f8d577a16 | |
|
037826fe1b | |
|
78e3371c05 | |
|
dd7696f473 | |
|
90648d1c9d | |
|
9196599f30 | |
|
a4d428c83c | |
|
a3285df729 | |
|
0cc5ca1397 | |
|
98360061a8 | |
|
3f5294c734 | |
|
eb5526d75f | |
|
b772119977 | |
|
5ee38510a8 | |
|
3eed950d3c | |
|
c8450358c0 | |
|
5668987274 | |
|
ee6d8b094a | |
|
0e048c1ff5 | |
|
35d4cc23c8 | |
|
ea59e7fa58 | |
|
a07eb67865 | |
|
dd53021153 | |
|
7fea9b106c | |
|
d7ed2a5de2 | |
|
8370d4209d | |
|
32340a3e0e | |
|
b7ed041eed | |
|
a81957ff56 | |
|
b0f915bb09 | |
|
61d821ae8a | |
|
dbf967a860 | |
|
7cac1984f8 | |
|
aed4ea21d6 | |
|
13dd70f847 | |
|
a36d2ab111 | |
|
a1ceb1fbbf | |
|
00bc0609eb | |
|
5e77f8ad33 | |
|
2934195a8f | |
|
d746dc0a11 | |
|
f1ea4057fc | |
|
37121e9939 | |
|
69db287007 | |
|
b215dec8b8 | |
|
beba1bd8d6 | |
|
75b9acd791 | |
|
b4f0550a2b | |
|
fed93942b8 | |
|
4591d3f1da | |
|
ccabb1856c | |
|
4ec155d91b | |
|
1ed7fc1577 | |
|
22435a694a | |
|
6990e21b47 | |
|
89cb7479f4 | |
|
cd4c8239cd | |
|
09686741ad | |
|
41128b86fb | |
|
c574ec5c77 | |
|
d23a9115c8 | |
|
326a10ba01 | |
|
865c3bb17a | |
|
e57eafd86d | |
|
7db6d8a3d3 | |
|
cf760e4cc4 | |
|
aa7f8b97f0 | |
|
baa13313e8 | |
|
5db43ad1aa | |
|
f1b0eb154d | |
|
3d0cd62c98 | |
|
eca299b3ad | |
|
91fa8cf7d6 | |
|
1d31726e57 | |
|
efbb69a998 | |
|
9cc9241b01 | |
|
aab84b80af | |
|
2bb58d6e1b | |
|
e8568a8ea2 | |
|
7ae703e1da | |
|
f3d9a55eb7 | |
|
2f5deb1a3a | |
|
145dfc70c2 | |
|
42d2d776a8 | |
|
d0b3b35981 | |
|
62f95b651b | |
|
fc40209edc | |
|
7bff3eebe6 | |
|
e2c70d9f0b | |
|
4e87fd25a4 | |
|
32b101ed8f | |
|
44b4b35431 | |
|
0ec57a1b03 | |
|
843b420cd1 | |
|
a2c04c1b23 | |
|
616d7e7b05 | |
|
f80a303e3f | |
|
72b9ffe583 | |
|
0dbdfa386d | |
|
b128f13e0b | |
|
cc2989bb59 | |
|
9ff353e509 | |
|
8e1709944f | |
|
8928bd4ab8 | |
|
a79c0ee80a | |
|
078f94edd9 | |
|
51721c2163 | |
|
4126b511fb | |
|
a0b1d25f49 | |
|
3fc7ccf88a | |
|
59f9779f19 | |
|
d8db02f872 | |
|
7cadadb8ec | |
|
c3eb16cd75 | |
|
20ce4daa4a | |
|
f9ec8de7b6 | |
|
82c265f168 | |
|
5c0aaaa8bc | |
|
4ea74d8a0a | |
|
dd33ec82cb | |
|
402cb1bc22 | |
|
6d6bcd1dea | |
|
515f38b3c7 | |
|
b3ba6fe5a2 | |
|
4420bcaaa9 | |
|
65e2bf3895 | |
|
c363bdd1ca | |
|
dbfeb72bc5 | |
|
27c9114c58 | |
|
71098a8569 | |
|
62bbd571e7 | |
|
a84f37562e | |
|
08e170e24a | |
|
340dd9c27c | |
|
253f29da2b | |
|
767e1ef04a | |
|
0467e999ee | |
|
c3c0fd2412 | |
|
be833a07f2 | |
|
bca1f0bab6 | |
|
015961b4fc | |
|
bdc19b2cc0 | |
|
1638b8974f | |
|
08567f43c8 | |
|
e65b2a0ecb | |
|
00478ec57b | |
|
1a46aea242 | |
|
0844c8f742 | |
|
41213c7422 | |
|
2334906534 | |
|
c94a0ba802 | |
|
29e6a90b10 | |
|
09c9a5c254 | |
|
0c540f1f39 | |
|
0e3c10fd74 | |
|
23c01b9fa3 | |
|
81cba71190 | |
|
3dfbfac268 | |
|
5097d7ca0f |
|
@ -0,0 +1,72 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
ij_continuation_indent_size = 8
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Following the rules of the Google Java Style Guide.
|
||||
# See https://google.github.io/styleguide/javaguide.html
|
||||
[*.java]
|
||||
max_line_length = 120
|
||||
|
||||
ij_java_do_not_wrap_after_single_annotation_in_parameter = true
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_class_count_to_use_import_on_demand = 999
|
||||
ij_java_names_count_to_use_import_on_demand = 999
|
||||
ij_java_packages_to_use_import_on_demand = unset
|
||||
ij_java_imports_layout = $*,|,*
|
||||
ij_java_doc_align_param_comments = true
|
||||
ij_java_doc_align_exception_comments = true
|
||||
ij_java_doc_add_p_tag_on_empty_lines = false
|
||||
ij_java_doc_do_not_wrap_if_one_line = true
|
||||
ij_java_doc_keep_empty_parameter_tag = false
|
||||
ij_java_doc_keep_empty_throws_tag = false
|
||||
ij_java_doc_keep_empty_return_tag = false
|
||||
ij_java_doc_preserve_line_breaks = true
|
||||
ij_java_doc_indent_on_continuation = true
|
||||
ij_java_keep_control_statement_in_one_line = false
|
||||
ij_java_keep_blank_lines_in_code = 1
|
||||
ij_java_align_multiline_parameters = false
|
||||
ij_java_align_multiline_resources = false
|
||||
ij_java_align_multiline_for = true
|
||||
ij_java_space_before_array_initializer_left_brace = true
|
||||
ij_java_call_parameters_wrap = normal
|
||||
ij_java_method_parameters_wrap = normal
|
||||
ij_java_extends_list_wrap = normal
|
||||
ij_java_throws_keyword_wrap = normal
|
||||
ij_java_method_call_chain_wrap = normal
|
||||
ij_java_binary_operation_wrap = normal
|
||||
ij_java_binary_operation_sign_on_next_line = true
|
||||
ij_java_ternary_operation_wrap = normal
|
||||
ij_java_ternary_operation_signs_on_next_line = true
|
||||
ij_java_keep_simple_methods_in_one_line = true
|
||||
ij_java_keep_simple_lambdas_in_one_line = true
|
||||
ij_java_keep_simple_classes_in_one_line = true
|
||||
ij_java_for_statement_wrap = normal
|
||||
ij_java_array_initializer_wrap = normal
|
||||
ij_java_wrap_comments = true
|
||||
ij_java_if_brace_force = always
|
||||
ij_java_do_while_brace_force = always
|
||||
ij_java_while_brace_force = always
|
||||
ij_java_for_brace_force = always
|
||||
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||
|
||||
[{*.json,*.json5}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
ij_smart_tabs = false
|
||||
|
||||
[*.yaml]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
|
@ -3,4 +3,3 @@
|
|||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
|
|
|
@ -18,6 +18,6 @@ jobs:
|
|||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@cfb60706e18bc85e8aec535e3c577abe8f70378e
|
||||
- uses: amannn/action-semantic-pull-request@335288255954904a41ddda8947c8f2c844b8bfeb
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -9,35 +9,36 @@ 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@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@a1c6c9c8677803c9f4bd31e0f15ac0844258f955
|
||||
- uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597
|
||||
with:
|
||||
java-version: '8'
|
||||
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@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
|
||||
uses: actions/cache@640a1c2554105b57832a23eea0b4672fc7a790d5
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
key: ${{ runner.os }}-17-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
${{ runner.os }}-17-maven-
|
||||
|
||||
- name: Configure GPG Key
|
||||
run: |
|
||||
|
@ -49,7 +50,7 @@ jobs:
|
|||
run: mvn --batch-mode --update-snapshots verify
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4.3.1
|
||||
uses: codecov/codecov-action@v5.4.3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
|
||||
flags: unittests # optional
|
||||
|
@ -60,11 +61,11 @@ jobs:
|
|||
# Add -SNAPSHOT before deploy
|
||||
- name: Add SNAPSHOT
|
||||
run: mvn versions:set -DnewVersion='${project.version}-SNAPSHOT'
|
||||
|
||||
|
||||
- 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 }}
|
||||
|
|
|
@ -7,36 +7,46 @@ permissions:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
build:
|
||||
- java: 17
|
||||
profile: codequality
|
||||
- java: 11
|
||||
profile: java11
|
||||
name: with Java ${{ matrix.build.java }}
|
||||
runs-on: ${{ matrix.os}}
|
||||
steps:
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b
|
||||
uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
|
||||
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@a1c6c9c8677803c9f4bd31e0f15ac0844258f955
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
java-version: ${{ matrix.build.java }}
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@84d6ead480f493c32a39f012db4b9dfb02e8868b
|
||||
uses: github/codeql-action/init@7710ed11e398ea99c7f7004c2b2e0f580458db42
|
||||
with:
|
||||
languages: java
|
||||
|
||||
- name: Cache local Maven repository
|
||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
|
||||
uses: actions/cache@640a1c2554105b57832a23eea0b4672fc7a790d5
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}${{ matrix.build.java }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}${{ matrix.build.java }}-maven-
|
||||
|
||||
- name: Verify with Maven
|
||||
run: mvn --batch-mode --update-snapshots --activate-profiles e2e verify
|
||||
run: mvn --batch-mode --update-snapshots --activate-profiles e2e,${{ matrix.build.profile }} verify
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4.3.1
|
||||
- if: matrix.build.java == '17'
|
||||
name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5.4.3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
|
||||
flags: unittests # optional
|
||||
|
@ -45,4 +55,4 @@ jobs:
|
|||
verbose: true # optional (default = false)
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@84d6ead480f493c32a39f012db4b9dfb02e8868b
|
||||
uses: github/codeql-action/analyze@7710ed11e398ea99c7f7004c2b2e0f580458db42
|
||||
|
|
|
@ -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@a37ac6e4f6449ce8b3f7607e4d97d0146028dc0b
|
||||
- uses: googleapis/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
default-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
|
||||
|
||||
# These steps are only run if this was a merged release-please PR
|
||||
- name: checkout
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b
|
||||
- name: Set up JDK 8
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
uses: actions/setup-java@a1c6c9c8677803c9f4bd31e0f15ac0844258f955
|
||||
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
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@ae2b61dbc685e60e4427b2e8ed4f0135c6ea8597
|
||||
with:
|
||||
java-version: '8'
|
||||
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 }}
|
||||
|
|
|
@ -29,16 +29,16 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b
|
||||
uses: actions/checkout@09d2acae674a48949e3602304ab46fd20ae0c42f
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@84d6ead480f493c32a39f012db4b9dfb02e8868b
|
||||
uses: github/codeql-action/init@7710ed11e398ea99c7f7004c2b2e0f580458db42
|
||||
with:
|
||||
languages: java
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@84d6ead480f493c32a39f012db4b9dfb02e8868b
|
||||
uses: github/codeql-action/autobuild@7710ed11e398ea99c7f7004c2b2e0f580458db42
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@84d6ead480f493c32a39f012db4b9dfb02e8868b
|
||||
uses: github/codeql-action/analyze@7710ed11e398ea99c7f7004c2b2e0f580458db42
|
||||
|
|
|
@ -9,4 +9,7 @@ target
|
|||
.DS_Store
|
||||
|
||||
# vscode stuff - we may want to use a more specific pattern later if we'd like to suggest editor configurations
|
||||
.vscode/
|
||||
.vscode/
|
||||
|
||||
# used for spec compliance tooling
|
||||
java-report.json
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "test-harness"]
|
||||
path = test-harness
|
||||
url = https://github.com/open-feature/test-harness
|
||||
[submodule "spec"]
|
||||
path = spec
|
||||
url = https://github.com/open-feature/spec/
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
wrapperVersion=3.3.2
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
|
|
@ -1 +1 @@
|
|||
{".":"1.8.0"}
|
||||
{".":"1.16.0"}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[spec]
|
||||
file_extension=java
|
||||
multiline_regex=@Specification\((?P<innards>.*?)\)\s*$
|
||||
number_subregex=number\s*=\s*['"](.*?)['"]
|
||||
text_subregex=text\s*=\s*['"](.*)['"]
|
717
CHANGELOG.md
717
CHANGELOG.md
|
@ -1,5 +1,722 @@
|
|||
# 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)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency org.slf4j:slf4j-api to v2.0.17 ([#1348](https://github.com/open-feature/java-sdk/issues/1348)) ([2ec7c6c](https://github.com/open-feature/java-sdk/commit/2ec7c6c7ff704380fdfd8116378adf78734e4f2b))
|
||||
* **deps:** update junit5 monorepo ([#1344](https://github.com/open-feature/java-sdk/issues/1344)) ([d95e270](https://github.com/open-feature/java-sdk/commit/d95e2706532259bd5739e5b4ea4813ef9f2196a6))
|
||||
* **deps:** update junit5 monorepo ([#1373](https://github.com/open-feature/java-sdk/issues/1373)) ([6b65e26](https://github.com/open-feature/java-sdk/commit/6b65e26c7439895652c3f64f2b4a7307a7ca582e))
|
||||
* equals and hashcode of several classes ([69b571e](https://github.com/open-feature/java-sdk/commit/69b571eda73b6f43c99864420b8663ae54ebf0ad))
|
||||
* equals and hashcode of several classes ([#1364](https://github.com/open-feature/java-sdk/issues/1364)) ([69b571e](https://github.com/open-feature/java-sdk/commit/69b571eda73b6f43c99864420b8663ae54ebf0ad))
|
||||
* hooks not run in NOT_READY/FATAL ([#1392](https://github.com/open-feature/java-sdk/issues/1392)) ([24ef9dd](https://github.com/open-feature/java-sdk/commit/24ef9dd2903d01ec029b70cd1e39e71ffe327499))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/cache digest to 5a3ec84 ([#1380](https://github.com/open-feature/java-sdk/issues/1380)) ([8359ef1](https://github.com/open-feature/java-sdk/commit/8359ef13bb935ac1d144787cfd7181814a0b286c))
|
||||
* **deps:** update actions/cache digest to 7921ae2 ([#1337](https://github.com/open-feature/java-sdk/issues/1337)) ([3920c63](https://github.com/open-feature/java-sdk/commit/3920c638a49caddfb07041f812cc6bc0bf3101f9))
|
||||
* **deps:** update actions/cache digest to d4323d4 ([#1353](https://github.com/open-feature/java-sdk/issues/1353)) ([5901797](https://github.com/open-feature/java-sdk/commit/59017977a487a36c8a39f63b83299bc657134c0d))
|
||||
* **deps:** update actions/setup-java digest to 3b6c050 ([#1391](https://github.com/open-feature/java-sdk/issues/1391)) ([7536679](https://github.com/open-feature/java-sdk/commit/753667925a8803b3b227f762936ae397dde95484))
|
||||
* **deps:** update actions/setup-java digest to 799ee7c ([#1359](https://github.com/open-feature/java-sdk/issues/1359)) ([31444d6](https://github.com/open-feature/java-sdk/commit/31444d6c8f30f0dd35debacc9dab8da7397e11ed))
|
||||
* **deps:** update actions/setup-java digest to b8ebb8b ([#1381](https://github.com/open-feature/java-sdk/issues/1381)) ([2239f05](https://github.com/open-feature/java-sdk/commit/2239f054b90734dde6cdd4a23daec1c1daa96f07))
|
||||
* **deps:** update amannn/action-semantic-pull-request digest to 04501d4 ([#1390](https://github.com/open-feature/java-sdk/issues/1390)) ([87c06d9](https://github.com/open-feature/java-sdk/commit/87c06d9edd935287daf7ebc8db1e7da4831531de))
|
||||
* **deps:** update codecov/codecov-action action to v5.4.0 ([#1351](https://github.com/open-feature/java-sdk/issues/1351)) ([b133c2f](https://github.com/open-feature/java-sdk/commit/b133c2fa527a0dddb6de7f7781a00fc84feaa813))
|
||||
* **deps:** update dependency com.diffplug.spotless:spotless-maven-plugin to v2.44.3 ([#1341](https://github.com/open-feature/java-sdk/issues/1341)) ([5de33c0](https://github.com/open-feature/java-sdk/commit/5de33c02a675db6ca5966bfa3f58d99c8e53e36b))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.1.0 ([#1332](https://github.com/open-feature/java-sdk/issues/1332)) ([cdcdc14](https://github.com/open-feature/java-sdk/commit/cdcdc143ea5ad2f003cb3f5450ec78314e619ea3))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.2.0 ([#1360](https://github.com/open-feature/java-sdk/issues/1360)) ([ecea9df](https://github.com/open-feature/java-sdk/commit/ecea9df932ee4874613f219b73640fe964c99593))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.9.3.0 ([#1375](https://github.com/open-feature/java-sdk/issues/1375)) ([de3e213](https://github.com/open-feature/java-sdk/commit/de3e213ac8b8931121904a3d12929405512e74dd))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.2 ([#1355](https://github.com/open-feature/java-sdk/issues/1355)) ([2a1adca](https://github.com/open-feature/java-sdk/commit/2a1adca8c2ed8d61d51530969290793a5d3d15f3))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.3 ([#1384](https://github.com/open-feature/java-sdk/issues/1384)) ([b6becac](https://github.com/open-feature/java-sdk/commit/b6becac2c4e0f98a8651cc2f77d4c0b081548991))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.4 ([#1387](https://github.com/open-feature/java-sdk/issues/1387)) ([cb574d9](https://github.com/open-feature/java-sdk/commit/cb574d93b6210c89a188aa104ef4f1db68daf1c0))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.2 ([#1356](https://github.com/open-feature/java-sdk/issues/1356)) ([dd83114](https://github.com/open-feature/java-sdk/commit/dd83114c4d9389753575392fafcd56585d7178ae))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.3 ([#1385](https://github.com/open-feature/java-sdk/issues/1385)) ([4125ae8](https://github.com/open-feature/java-sdk/commit/4125ae83801a9f485059a9edaca090ee47b7632f))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.4 ([#1388](https://github.com/open-feature/java-sdk/issues/1388)) ([d8f6514](https://github.com/open-feature/java-sdk/commit/d8f6514598d53f43cb084ee746742a59d271363b))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.0 ([#1342](https://github.com/open-feature/java-sdk/issues/1342)) ([88a778c](https://github.com/open-feature/java-sdk/commit/88a778cc03e112d45756428d1f0ae1ef0fe02c84))
|
||||
* **deps:** update dependency org.awaitility:awaitility to v4.3.0 ([#1343](https://github.com/open-feature/java-sdk/issues/1343)) ([1504d0f](https://github.com/open-feature/java-sdk/commit/1504d0f7982757a2b413eda593ce7057b90519e5))
|
||||
* **deps:** update dependency org.mockito:mockito-core to v5.15.2 ([#1339](https://github.com/open-feature/java-sdk/issues/1339)) ([4817864](https://github.com/open-feature/java-sdk/commit/4817864fd7ae70c1e19c3c09e82e1fb03dd88942))
|
||||
* **deps:** update dependency org.mockito:mockito-core to v5.16.0 ([#1358](https://github.com/open-feature/java-sdk/issues/1358)) ([30b6d00](https://github.com/open-feature/java-sdk/commit/30b6d004aaf3464547805f7eda6fad0e122de4f9))
|
||||
* **deps:** update dependency org.mockito:mockito-core to v5.16.1 ([#1376](https://github.com/open-feature/java-sdk/issues/1376)) ([9750f75](https://github.com/open-feature/java-sdk/commit/9750f75d04beb8339fc2e972f0ee97120eaff354))
|
||||
* **deps:** update github/codeql-action digest to 1bb15d0 ([#1336](https://github.com/open-feature/java-sdk/issues/1336)) ([e163ce1](https://github.com/open-feature/java-sdk/commit/e163ce1c060d0dc8812e4a8a3b37f52b0156324d))
|
||||
* **deps:** update github/codeql-action digest to 486ab5a ([#1389](https://github.com/open-feature/java-sdk/issues/1389)) ([85fd5e0](https://github.com/open-feature/java-sdk/commit/85fd5e0997ff1a5e5d7226d8bbfe2775769a6ca6))
|
||||
* **deps:** update github/codeql-action digest to 56b25d5 ([#1365](https://github.com/open-feature/java-sdk/issues/1365)) ([959e675](https://github.com/open-feature/java-sdk/commit/959e675e4c2363e5fd80d1d2f1edbfab11794fc8))
|
||||
* **deps:** update github/codeql-action digest to 608ccd6 ([#1361](https://github.com/open-feature/java-sdk/issues/1361)) ([67b34f8](https://github.com/open-feature/java-sdk/commit/67b34f84a373512013ab2f7649faaddfd2d61048))
|
||||
* **deps:** update github/codeql-action digest to 6349095 ([#1378](https://github.com/open-feature/java-sdk/issues/1378)) ([dbf92df](https://github.com/open-feature/java-sdk/commit/dbf92df33bf5657d50dc3b2f129207b0097c1f27))
|
||||
* **deps:** update github/codeql-action digest to 6a151cd ([#1377](https://github.com/open-feature/java-sdk/issues/1377)) ([7065655](https://github.com/open-feature/java-sdk/commit/706565581d78856dd73605b1a16b131f974c0731))
|
||||
* **deps:** update github/codeql-action digest to 70df9de ([#1372](https://github.com/open-feature/java-sdk/issues/1372)) ([d233480](https://github.com/open-feature/java-sdk/commit/d233480912f1d5e095f5034f36a838535d1ecdff))
|
||||
* **deps:** update github/codeql-action digest to 7254660 ([#1368](https://github.com/open-feature/java-sdk/issues/1368)) ([d54c68a](https://github.com/open-feature/java-sdk/commit/d54c68a8e9e4a0f67c99e7d76621a1c5724e4cd1))
|
||||
* **deps:** update github/codeql-action digest to 80f9930 ([#1357](https://github.com/open-feature/java-sdk/issues/1357)) ([6c03e5d](https://github.com/open-feature/java-sdk/commit/6c03e5d84aacee11f5b8e608a6114c11fced72b8))
|
||||
* **deps:** update github/codeql-action digest to 8392354 ([#1352](https://github.com/open-feature/java-sdk/issues/1352)) ([989f4ae](https://github.com/open-feature/java-sdk/commit/989f4ae54263b46ca2c81561acc70b39918c382d))
|
||||
* **deps:** update github/codeql-action digest to 8c1551c ([#1333](https://github.com/open-feature/java-sdk/issues/1333)) ([859a36c](https://github.com/open-feature/java-sdk/commit/859a36cbfafc94d4601b87d304237e6ddf97c08d))
|
||||
* **deps:** update github/codeql-action digest to 8c69433 ([#1347](https://github.com/open-feature/java-sdk/issues/1347)) ([6987568](https://github.com/open-feature/java-sdk/commit/698756856ba40e98d91ccf661dab409798861aa5))
|
||||
* **deps:** update github/codeql-action digest to 97aac9b ([#1350](https://github.com/open-feature/java-sdk/issues/1350)) ([7df9565](https://github.com/open-feature/java-sdk/commit/7df9565691731d164b534116b8a6b933b171d103))
|
||||
* **deps:** update github/codeql-action digest to a8849fb ([#1345](https://github.com/open-feature/java-sdk/issues/1345)) ([de64edd](https://github.com/open-feature/java-sdk/commit/de64eddfb3a6cc117bb108dbcf167830e9f6729d))
|
||||
* **deps:** update github/codeql-action digest to acadfed ([#1335](https://github.com/open-feature/java-sdk/issues/1335)) ([5436eb0](https://github.com/open-feature/java-sdk/commit/5436eb0d5db3a0e9bd9289fbef57b9eeada0a667))
|
||||
* **deps:** update github/codeql-action digest to b2e6519 ([#1366](https://github.com/open-feature/java-sdk/issues/1366)) ([d00e4b5](https://github.com/open-feature/java-sdk/commit/d00e4b5b24621aa55085827fbe6ea982491376de))
|
||||
* **deps:** update github/codeql-action digest to b46b37a ([#1367](https://github.com/open-feature/java-sdk/issues/1367)) ([c550d59](https://github.com/open-feature/java-sdk/commit/c550d597227bfc1e0e17357139f1fd8a87593be0))
|
||||
* **deps:** update github/codeql-action digest to bd1d9ab ([#1383](https://github.com/open-feature/java-sdk/issues/1383)) ([922e17e](https://github.com/open-feature/java-sdk/commit/922e17e677e15690e3df2fe93a961f16f21ff283))
|
||||
* **deps:** update github/codeql-action digest to c50c157 ([#1379](https://github.com/open-feature/java-sdk/issues/1379)) ([d61c33e](https://github.com/open-feature/java-sdk/commit/d61c33e466336c7120b870ca5e3843eba5f7175c))
|
||||
* **deps:** update github/codeql-action digest to d99c7e8 ([#1338](https://github.com/open-feature/java-sdk/issues/1338)) ([4e535fd](https://github.com/open-feature/java-sdk/commit/4e535fd10fac742ca472faa62c941fa51b282ca7))
|
||||
* **deps:** update github/codeql-action digest to dc49dca ([#1369](https://github.com/open-feature/java-sdk/issues/1369)) ([f8df5fb](https://github.com/open-feature/java-sdk/commit/f8df5fb84a765af917587dd509f9cec38103f787))
|
||||
* **deps:** update github/codeql-action digest to e0ea141 ([#1386](https://github.com/open-feature/java-sdk/issues/1386)) ([387e5f2](https://github.com/open-feature/java-sdk/commit/387e5f2e3bd24ccea6691b0d6dbfe542cfd05b52))
|
||||
* **deps:** update github/codeql-action digest to ff79de6 ([#1340](https://github.com/open-feature/java-sdk/issues/1340)) ([50b45b2](https://github.com/open-feature/java-sdk/commit/50b45b2be442bb89a431c9bcc45d825f63bd93a6))
|
||||
* update build and tooling to utilize new java version ([#1321](https://github.com/open-feature/java-sdk/issues/1321)) ([90217b2](https://github.com/open-feature/java-sdk/commit/90217b2083a2ba92c623365dc450326d49b46fab))
|
||||
|
||||
## [1.14.1](https://github.com/open-feature/java-sdk/compare/v1.14.0...v1.14.1) (2025-02-14)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.21.0 ([#1312](https://github.com/open-feature/java-sdk/issues/1312)) ([208411e](https://github.com/open-feature/java-sdk/commit/208411e72338e37bf477ac0b784bbbbe0309b922))
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.21.1 ([#1317](https://github.com/open-feature/java-sdk/issues/1317)) ([b797883](https://github.com/open-feature/java-sdk/commit/b7978832b786fe081169ff0efeb702218300c622))
|
||||
* possible event-related deadlocks with some providers ([#1314](https://github.com/open-feature/java-sdk/issues/1314)) ([c33ac2d](https://github.com/open-feature/java-sdk/commit/c33ac2d9b2e91b85fffb3c21653912fe82006351))
|
||||
* TrackingEventDetails interface to include numeric getValue() call ([#1328](https://github.com/open-feature/java-sdk/issues/1328)) ([08c38fb](https://github.com/open-feature/java-sdk/commit/08c38fb553d82a42682c3eb9239329f770063898))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/cache digest to 9fa7e61 ([#1324](https://github.com/open-feature/java-sdk/issues/1324)) ([69cdc77](https://github.com/open-feature/java-sdk/commit/69cdc772a639470dd223bf70ef6e9f8bc4d93dea))
|
||||
* **deps:** update actions/checkout digest to 85e6279 ([#1287](https://github.com/open-feature/java-sdk/issues/1287)) ([640e35e](https://github.com/open-feature/java-sdk/commit/640e35e85375e3098f61b7397432d80a95502bdd))
|
||||
* **deps:** update actions/setup-java digest to 28b532b ([#1296](https://github.com/open-feature/java-sdk/issues/1296)) ([874e86d](https://github.com/open-feature/java-sdk/commit/874e86df5c22a1e5771ca16c76aa13039b5f9b65))
|
||||
* **deps:** update actions/setup-java digest to 3a4f6e1 ([#1306](https://github.com/open-feature/java-sdk/issues/1306)) ([ba9cc4b](https://github.com/open-feature/java-sdk/commit/ba9cc4b85a1082d638d49b9d2d0a4ed5a45f09ee))
|
||||
* **deps:** update actions/setup-java digest to 51ab6d2 ([#1288](https://github.com/open-feature/java-sdk/issues/1288)) ([c69d3a4](https://github.com/open-feature/java-sdk/commit/c69d3a4bd137c1d6baa47c14228bfe8f96555676))
|
||||
* **deps:** update actions/setup-java digest to 99d3141 ([#1285](https://github.com/open-feature/java-sdk/issues/1285)) ([32a3933](https://github.com/open-feature/java-sdk/commit/32a39335de8e61650905fc96dc1a73e65f1fe9f8))
|
||||
* **deps:** update codecov/codecov-action action to v5.2.0 ([#1298](https://github.com/open-feature/java-sdk/issues/1298)) ([531fc38](https://github.com/open-feature/java-sdk/commit/531fc385b662c5b7b334fee298fc9fe1283c78fb))
|
||||
* **deps:** update codecov/codecov-action action to v5.3.0 ([#1301](https://github.com/open-feature/java-sdk/issues/1301)) ([f7f6586](https://github.com/open-feature/java-sdk/commit/f7f6586d72e3f112a7dafc8f77de273ed49ccc4b))
|
||||
* **deps:** update codecov/codecov-action action to v5.3.1 ([#1303](https://github.com/open-feature/java-sdk/issues/1303)) ([f9fa54b](https://github.com/open-feature/java-sdk/commit/f9fa54be493e1d0843b709008eb0f047e7580d47))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.16.0 ([#1289](https://github.com/open-feature/java-sdk/issues/1289)) ([0b5b423](https://github.com/open-feature/java-sdk/commit/0b5b423bdd378bb1db3e10fe5da7fa2c937a4610))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.16.1 ([#1292](https://github.com/open-feature/java-sdk/issues/1292)) ([0af9f29](https://github.com/open-feature/java-sdk/commit/0af9f2901f88b5ef9bed0c570d426939a55af3cf))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.0 ([#1309](https://github.com/open-feature/java-sdk/issues/1309)) ([cda3405](https://github.com/open-feature/java-sdk/commit/cda34053f7e39318205a181ef93c825bab2ed9fc))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.17.1 ([#1329](https://github.com/open-feature/java-sdk/issues/1329)) ([9ab2618](https://github.com/open-feature/java-sdk/commit/9ab26182eae4974b60d166777c51dfcb07957150))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.16.0 ([#1290](https://github.com/open-feature/java-sdk/issues/1290)) ([6c4205a](https://github.com/open-feature/java-sdk/commit/6c4205a00817af260ef9b90f54ce878cad33f75a))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.16.1 ([#1293](https://github.com/open-feature/java-sdk/issues/1293)) ([6071932](https://github.com/open-feature/java-sdk/commit/6071932cb4207dc83cdedfa67c8a69ed71d9c26a))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.0 ([#1310](https://github.com/open-feature/java-sdk/issues/1310)) ([40fa173](https://github.com/open-feature/java-sdk/commit/40fa1733382f4c476a1228c6499044ad83c8f3c4))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.17.1 ([#1330](https://github.com/open-feature/java-sdk/issues/1330)) ([4ba5695](https://github.com/open-feature/java-sdk/commit/4ba5695eeea6a7ab2fe1d2c595fa482d4b7868dc))
|
||||
* **deps:** update dependency org.assertj:assertj-core to v3.27.3 ([#1291](https://github.com/open-feature/java-sdk/issues/1291)) ([a5eb21d](https://github.com/open-feature/java-sdk/commit/a5eb21d1a2e6945a4455cacde898bc913bddb96d))
|
||||
* **deps:** update github/codeql-action digest to 0701025 ([#1311](https://github.com/open-feature/java-sdk/issues/1311)) ([9a1e9ab](https://github.com/open-feature/java-sdk/commit/9a1e9abd64220c8d8706f2a64e041ef3f37e1a43))
|
||||
* **deps:** update github/codeql-action digest to 08bc0cf ([#1313](https://github.com/open-feature/java-sdk/issues/1313)) ([37ed6a4](https://github.com/open-feature/java-sdk/commit/37ed6a424cdc013ed74c9881826cc56c93ae8228))
|
||||
* **deps:** update github/codeql-action digest to 0a35e8f ([#1316](https://github.com/open-feature/java-sdk/issues/1316)) ([26e1d7f](https://github.com/open-feature/java-sdk/commit/26e1d7fff342a32880542efa87b017aec506667e))
|
||||
* **deps:** update github/codeql-action digest to 0f1559a ([#1286](https://github.com/open-feature/java-sdk/issues/1286)) ([882d2dd](https://github.com/open-feature/java-sdk/commit/882d2dd5bdac007e8a3783efc54fa45faed22054))
|
||||
* **deps:** update github/codeql-action digest to 10a3f07 ([#1280](https://github.com/open-feature/java-sdk/issues/1280)) ([a3854d6](https://github.com/open-feature/java-sdk/commit/a3854d6ab1dba99f4db18f868e89fcc04418e306))
|
||||
* **deps:** update github/codeql-action digest to 1c15a48 ([#1325](https://github.com/open-feature/java-sdk/issues/1325)) ([3baf0df](https://github.com/open-feature/java-sdk/commit/3baf0df966f8212864aa7e57bc3d3d09d324fe11))
|
||||
* **deps:** update github/codeql-action digest to 1efc6bb ([#1281](https://github.com/open-feature/java-sdk/issues/1281)) ([8a1ab7e](https://github.com/open-feature/java-sdk/commit/8a1ab7ea18aff4ee5a6a2fdd1f805b08e51a50a3))
|
||||
* **deps:** update github/codeql-action digest to 24e1c2d ([#1315](https://github.com/open-feature/java-sdk/issues/1315)) ([46903c6](https://github.com/open-feature/java-sdk/commit/46903c6f275e5f9dc8884acf3f76f76efcfc58bd))
|
||||
* **deps:** update github/codeql-action digest to 3b4f4d9 ([#1282](https://github.com/open-feature/java-sdk/issues/1282)) ([b390d5f](https://github.com/open-feature/java-sdk/commit/b390d5f0b0945948cd6b87e6486725d095d5ac8a))
|
||||
* **deps:** update github/codeql-action digest to 43cffee ([#1304](https://github.com/open-feature/java-sdk/issues/1304)) ([6874de6](https://github.com/open-feature/java-sdk/commit/6874de64ce589e853f5523019bfa9e1d60840baf))
|
||||
* **deps:** update github/codeql-action digest to 54b1c84 ([#1307](https://github.com/open-feature/java-sdk/issues/1307)) ([6f36434](https://github.com/open-feature/java-sdk/commit/6f36434c520dcef27deb04e04941693dc15acb2f))
|
||||
* **deps:** update github/codeql-action digest to 5f4f998 ([#1305](https://github.com/open-feature/java-sdk/issues/1305)) ([7916d76](https://github.com/open-feature/java-sdk/commit/7916d76635c5ab59dafe6d72058aad9cfcf05f4b))
|
||||
* **deps:** update github/codeql-action digest to 6063925 ([#1320](https://github.com/open-feature/java-sdk/issues/1320)) ([538140d](https://github.com/open-feature/java-sdk/commit/538140dfe713a421623b179e69b399f82200fe61))
|
||||
* **deps:** update github/codeql-action digest to 7e3036b ([#1300](https://github.com/open-feature/java-sdk/issues/1300)) ([3491956](https://github.com/open-feature/java-sdk/commit/34919561b73faa0cca489ad480e93cca9a854167))
|
||||
* **deps:** update github/codeql-action digest to 87fc816 ([#1277](https://github.com/open-feature/java-sdk/issues/1277)) ([c2a82db](https://github.com/open-feature/java-sdk/commit/c2a82dbdbafa134fae4b0c9aef88cf589e09aefa))
|
||||
* **deps:** update github/codeql-action digest to 93da9f2 ([#1283](https://github.com/open-feature/java-sdk/issues/1283)) ([45b3995](https://github.com/open-feature/java-sdk/commit/45b3995bdad9f1b05abb01455a9c8f57028cfde5))
|
||||
* **deps:** update github/codeql-action digest to affec20 ([#1323](https://github.com/open-feature/java-sdk/issues/1323)) ([8f3ced5](https://github.com/open-feature/java-sdk/commit/8f3ced590764760244cc81ac10c939ca62504dfe))
|
||||
* **deps:** update github/codeql-action digest to b44b19f ([#1297](https://github.com/open-feature/java-sdk/issues/1297)) ([305e032](https://github.com/open-feature/java-sdk/commit/305e0329e78116fe697240e420879ac85012d698))
|
||||
* **deps:** update github/codeql-action digest to d90e07f ([#1294](https://github.com/open-feature/java-sdk/issues/1294)) ([5671184](https://github.com/open-feature/java-sdk/commit/5671184e7f76f979d631c18bb2ebfb15dccfb207))
|
||||
* **deps:** update github/codeql-action digest to db7177a ([#1279](https://github.com/open-feature/java-sdk/issues/1279)) ([b997946](https://github.com/open-feature/java-sdk/commit/b997946db1c7663b7ebb775ad45cdb2b0aaeb291))
|
||||
* **deps:** update github/codeql-action digest to e7c0c9d ([#1302](https://github.com/open-feature/java-sdk/issues/1302)) ([78adc77](https://github.com/open-feature/java-sdk/commit/78adc77c23da6116e1f58b3a45dc283c3c58837b))
|
||||
* **deps:** update github/codeql-action digest to e9987ad ([#1308](https://github.com/open-feature/java-sdk/issues/1308)) ([99d8185](https://github.com/open-feature/java-sdk/commit/99d818572a3407ca6b25f6e91f69ef3e83bdc657))
|
||||
* **deps:** update github/codeql-action digest to f89b8a7 ([#1295](https://github.com/open-feature/java-sdk/issues/1295)) ([122e82f](https://github.com/open-feature/java-sdk/commit/122e82f8431fb116ae3b147f7e2245d7f90b1c77))
|
||||
|
||||
## [1.14.0](https://github.com/open-feature/java-sdk/compare/v1.13.0...v1.14.0) (2025-01-10)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
The signature of the `finallyAfter` hook stage has been changed. The signature now includes the `evaluation details`, as per the [OpenFeature specification](https://openfeature.dev/specification/sections/hooks#requirement-438). Note that since hooks are still `experimental,` this does not constitute a change requiring a new major version. To migrate, update any hook that implements the `finallyAfter` stage to accept `evaluation details` as the second argument.
|
||||
|
||||
* Add evaluation details to finally hook stage [#1246](https://github.com/open-feature/java-sdk/issues/1246) ([#1262](https://github.com/open-feature/java-sdk/issues/1262)) ([ae85278](https://github.com/open-feature/java-sdk/commit/ae85278c30eb5279b80ea73ec6b92db040ad0bb7))
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update junit5 monorepo ([#1251](https://github.com/open-feature/java-sdk/issues/1251)) ([834f720](https://github.com/open-feature/java-sdk/commit/834f72071806680353f42c750b04e36956736a9e))
|
||||
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
* Add evaluation details to finally hook stage [#1246](https://github.com/open-feature/java-sdk/issues/1246) ([#1262](https://github.com/open-feature/java-sdk/issues/1262)) ([ae85278](https://github.com/open-feature/java-sdk/commit/ae85278c30eb5279b80ea73ec6b92db040ad0bb7))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/cache digest to 36f1e14 ([#1274](https://github.com/open-feature/java-sdk/issues/1274)) ([d825ff8](https://github.com/open-feature/java-sdk/commit/d825ff83639a2bd902bf0559209c2b80e17e0316))
|
||||
* **deps:** update actions/cache digest to 53aa38c ([#1270](https://github.com/open-feature/java-sdk/issues/1270)) ([a1c558f](https://github.com/open-feature/java-sdk/commit/a1c558f4ffb95772bd141ab7660e2c5b065482f1))
|
||||
* **deps:** update actions/setup-java digest to 7136edc ([#1244](https://github.com/open-feature/java-sdk/issues/1244)) ([9acc861](https://github.com/open-feature/java-sdk/commit/9acc8612a5fa7ea086da476195154a007cb55b7e))
|
||||
* **deps:** update actions/setup-java digest to 7a6d8a8 ([#1248](https://github.com/open-feature/java-sdk/issues/1248)) ([86e18c5](https://github.com/open-feature/java-sdk/commit/86e18c5d28a9f5fdd7234274720ba7ddcb529268))
|
||||
* **deps:** update codecov/codecov-action action to v5.1.2 ([#1255](https://github.com/open-feature/java-sdk/issues/1255)) ([d274cda](https://github.com/open-feature/java-sdk/commit/d274cdac3780286a0b45865864b12c3e4cff9f4b))
|
||||
* **deps:** update dependency com.google.guava:guava to v33.4.0-jre ([#1253](https://github.com/open-feature/java-sdk/issues/1253)) ([f39c4b5](https://github.com/open-feature/java-sdk/commit/f39c4b5af5e341bfec230d4cecd2037fc5430400))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.11 ([#1249](https://github.com/open-feature/java-sdk/issues/1249)) ([4440cda](https://github.com/open-feature/java-sdk/commit/4440cda6a5b42a903ba11835a975bf6247de845f))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.11 ([#1250](https://github.com/open-feature/java-sdk/issues/1250)) ([6772d3f](https://github.com/open-feature/java-sdk/commit/6772d3f3943fb3b7f7522c80b732aa058fd03bb9))
|
||||
* **deps:** update dependency org.assertj:assertj-core to v3.27.0 ([#1258](https://github.com/open-feature/java-sdk/issues/1258)) ([c62ade3](https://github.com/open-feature/java-sdk/commit/c62ade3878dabf9194536d551f3316ba5c0ce5e1))
|
||||
* **deps:** update dependency org.assertj:assertj-core to v3.27.1 ([#1266](https://github.com/open-feature/java-sdk/issues/1266)) ([20bbb23](https://github.com/open-feature/java-sdk/commit/20bbb2337cb5afbee9b8d5143b45416673cb4154))
|
||||
* **deps:** update dependency org.assertj:assertj-core to v3.27.2 ([#1268](https://github.com/open-feature/java-sdk/issues/1268)) ([2e10d34](https://github.com/open-feature/java-sdk/commit/2e10d34920f57d863c09ce1522c9ccff20413f74))
|
||||
* **deps:** update github/codeql-action digest to 3407610 ([#1269](https://github.com/open-feature/java-sdk/issues/1269)) ([4086dea](https://github.com/open-feature/java-sdk/commit/4086dea703a950dcacc792be9a9346cc1fa8409d))
|
||||
* **deps:** update github/codeql-action digest to 4d64ab6 ([#1243](https://github.com/open-feature/java-sdk/issues/1243)) ([884f8fb](https://github.com/open-feature/java-sdk/commit/884f8fbf77c41e070526da0f73e136d4c3e41a4d))
|
||||
* **deps:** update github/codeql-action digest to 562042d ([#1254](https://github.com/open-feature/java-sdk/issues/1254)) ([6a79874](https://github.com/open-feature/java-sdk/commit/6a7987455ef7e46d40b835c7d8dbda29322e3b2d))
|
||||
* **deps:** update github/codeql-action digest to 5b6e617 ([#1263](https://github.com/open-feature/java-sdk/issues/1263)) ([f1817d8](https://github.com/open-feature/java-sdk/commit/f1817d8fef585f957de1cfb9222b03cb591ed2e9))
|
||||
* **deps:** update github/codeql-action digest to 64cc90b ([#1256](https://github.com/open-feature/java-sdk/issues/1256)) ([992c003](https://github.com/open-feature/java-sdk/commit/992c00396cb2fca6a6a7dc63d727b063a79386b6))
|
||||
* **deps:** update github/codeql-action digest to 7876007 ([#1260](https://github.com/open-feature/java-sdk/issues/1260)) ([fc6f35e](https://github.com/open-feature/java-sdk/commit/fc6f35e581cacb0ad149c58a5943ec1429ce25ca))
|
||||
* **deps:** update github/codeql-action digest to 78d0136 ([#1245](https://github.com/open-feature/java-sdk/issues/1245)) ([fd1c170](https://github.com/open-feature/java-sdk/commit/fd1c1702c6d4067c432c1522143266ddf470d18d))
|
||||
* **deps:** update github/codeql-action digest to 8975792 ([#1241](https://github.com/open-feature/java-sdk/issues/1241)) ([b0abfd0](https://github.com/open-feature/java-sdk/commit/b0abfd02cf9e97f7409df3296818ac990b429058))
|
||||
* **deps:** update github/codeql-action digest to 9d59969 ([#1252](https://github.com/open-feature/java-sdk/issues/1252)) ([482a5ae](https://github.com/open-feature/java-sdk/commit/482a5aef1005b2ebe2fdb9ee43243b6c2aeeadc8))
|
||||
* **deps:** update github/codeql-action digest to d01b25e ([#1257](https://github.com/open-feature/java-sdk/issues/1257)) ([6d60c96](https://github.com/open-feature/java-sdk/commit/6d60c962fbac48a13d86271b361fb0cfd91a5342))
|
||||
* **deps:** update github/codeql-action digest to dd75594 ([#1247](https://github.com/open-feature/java-sdk/issues/1247)) ([6d169f5](https://github.com/open-feature/java-sdk/commit/6d169f55e235a071033a9bf1138484f09a5e472d))
|
||||
* **deps:** update github/codeql-action digest to e83e0a4 ([#1275](https://github.com/open-feature/java-sdk/issues/1275)) ([9c92ebb](https://github.com/open-feature/java-sdk/commit/9c92ebb1bdb23c80461f143753f2fb42956462e3))
|
||||
* **deps:** update github/codeql-action digest to fb65b6c ([#1273](https://github.com/open-feature/java-sdk/issues/1273)) ([3c97b7b](https://github.com/open-feature/java-sdk/commit/3c97b7baaf9eee719479c059cb923d8d64f2c25f))
|
||||
|
||||
## [1.13.0](https://github.com/open-feature/java-sdk/compare/v1.12.2...v1.13.0) (2024-12-07)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency org.projectlombok:lombok to v1.18.36 ([#1219](https://github.com/open-feature/java-sdk/issues/1219)) ([9cadc71](https://github.com/open-feature/java-sdk/commit/9cadc71d9d8a2a88f9c716c27eb939f423b95fa0))
|
||||
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
* add tracking as per spec ([#1228](https://github.com/open-feature/java-sdk/issues/1228)) ([64ad644](https://github.com/open-feature/java-sdk/commit/64ad644bdbb6a4535da8ec7628e74d5f41f7ebec))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/cache digest to 1bd1e32 ([#1237](https://github.com/open-feature/java-sdk/issues/1237)) ([da725d8](https://github.com/open-feature/java-sdk/commit/da725d89e03d499a37307cca47b2c51af5ac8782))
|
||||
* **deps:** update actions/checkout digest to 3b9b8c8 ([#1206](https://github.com/open-feature/java-sdk/issues/1206)) ([446e298](https://github.com/open-feature/java-sdk/commit/446e2987e9b80175dff0ea72de9f58ba8e0dd323))
|
||||
* **deps:** update actions/checkout digest to cbb7224 ([#1216](https://github.com/open-feature/java-sdk/issues/1216)) ([273efc6](https://github.com/open-feature/java-sdk/commit/273efc62a7bb2e3fe962036d82818eb1da43b197))
|
||||
* **deps:** update amannn/action-semantic-pull-request digest to 40166f0 ([#1212](https://github.com/open-feature/java-sdk/issues/1212)) ([d5228f5](https://github.com/open-feature/java-sdk/commit/d5228f5ccfa55753178425c55a02af1833168513))
|
||||
* **deps:** update codecov/codecov-action action to v5 ([#1217](https://github.com/open-feature/java-sdk/issues/1217)) ([7aa77b8](https://github.com/open-feature/java-sdk/commit/7aa77b8614401c56e8387d55382e4be115a7d1ef))
|
||||
* **deps:** update codecov/codecov-action action to v5.0.2 ([#1218](https://github.com/open-feature/java-sdk/issues/1218)) ([1b4947f](https://github.com/open-feature/java-sdk/commit/1b4947f108c15a4777bb35bafb631a40c7e20e77))
|
||||
* **deps:** update codecov/codecov-action action to v5.0.3 ([#1223](https://github.com/open-feature/java-sdk/issues/1223)) ([e91194a](https://github.com/open-feature/java-sdk/commit/e91194ae16c1d68033a750050af18de68a618f61))
|
||||
* **deps:** update codecov/codecov-action action to v5.0.4 ([#1224](https://github.com/open-feature/java-sdk/issues/1224)) ([19ed5c7](https://github.com/open-feature/java-sdk/commit/19ed5c7c97dc286a85faae1c4906508f97191497))
|
||||
* **deps:** update codecov/codecov-action action to v5.0.6 ([#1226](https://github.com/open-feature/java-sdk/issues/1226)) ([13811dc](https://github.com/open-feature/java-sdk/commit/13811dcf254b604ec73b4df184d432f1dc404398))
|
||||
* **deps:** update codecov/codecov-action action to v5.0.7 ([#1227](https://github.com/open-feature/java-sdk/issues/1227)) ([234062c](https://github.com/open-feature/java-sdk/commit/234062cf338036b3b942b83c00b31191fb626432))
|
||||
* **deps:** update codecov/codecov-action action to v5.1.1 ([#1238](https://github.com/open-feature/java-sdk/issues/1238)) ([c5ad1b4](https://github.com/open-feature/java-sdk/commit/c5ad1b4d4f805a6ae070eabc6de38b37dd759c05))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.6.6 ([#1213](https://github.com/open-feature/java-sdk/issues/1213)) ([92c8791](https://github.com/open-feature/java-sdk/commit/92c87913ac417b8b3651290a4df828bdf5d501b9))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.10 ([#1202](https://github.com/open-feature/java-sdk/issues/1202)) ([d959059](https://github.com/open-feature/java-sdk/commit/d95905917730dcb8724fe166682ca773a536eb9b))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.8 ([#1195](https://github.com/open-feature/java-sdk/issues/1195)) ([309f28b](https://github.com/open-feature/java-sdk/commit/309f28b520a8f629a500c359b1f522ba687bcc6b))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.9 ([#1197](https://github.com/open-feature/java-sdk/issues/1197)) ([54a2345](https://github.com/open-feature/java-sdk/commit/54a234519f36ea803ec8574f27c94a9f754bf822))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.10 ([#1203](https://github.com/open-feature/java-sdk/issues/1203)) ([2bb2ed3](https://github.com/open-feature/java-sdk/commit/2bb2ed39928e0e15d369741df8b877c751e8d122))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.8 ([#1196](https://github.com/open-feature/java-sdk/issues/1196)) ([30eb2ce](https://github.com/open-feature/java-sdk/commit/30eb2ce082ae2854025be084da98fb856dbcd17c))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.9 ([#1198](https://github.com/open-feature/java-sdk/issues/1198)) ([e32a712](https://github.com/open-feature/java-sdk/commit/e32a712615f3b1be9cff61f1337d5b00c365c8f5))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-checkstyle-plugin to v3.6.0 ([#1188](https://github.com/open-feature/java-sdk/issues/1188)) ([89c7f85](https://github.com/open-feature/java-sdk/commit/89c7f85da436b9f16193948183a1ca54eea6ceef))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-dependency-plugin to v3.8.1 ([#1187](https://github.com/open-feature/java-sdk/issues/1187)) ([5c7c287](https://github.com/open-feature/java-sdk/commit/5c7c28706e4614061b042080820b9efd04afc342))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.5.2 ([#1199](https://github.com/open-feature/java-sdk/issues/1199)) ([08da9a3](https://github.com/open-feature/java-sdk/commit/08da9a34395a3e96dc2172f0f0533a4905cff204))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.11.1 ([#1201](https://github.com/open-feature/java-sdk/issues/1201)) ([a2a57ab](https://github.com/open-feature/java-sdk/commit/a2a57ab8f1161b5de3a112bbbdc421985baf304b))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.11.2 ([#1240](https://github.com/open-feature/java-sdk/issues/1240)) ([c87c6e7](https://github.com/open-feature/java-sdk/commit/c87c6e7a760e84a5e8d9a6d935ef35611d1de8ab))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-pmd-plugin to v3.26.0 ([#1189](https://github.com/open-feature/java-sdk/issues/1189)) ([d5082cd](https://github.com/open-feature/java-sdk/commit/d5082cd5f6907b6e7649813dbbea99cdeab20728))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.2 ([#1200](https://github.com/open-feature/java-sdk/issues/1200)) ([d2cb092](https://github.com/open-feature/java-sdk/commit/d2cb092b09966bc2d5a7548e35b71ab2e56e0dee))
|
||||
* **deps:** update dependency org.cyclonedx:cyclonedx-maven-plugin to v2.9.1 ([#1230](https://github.com/open-feature/java-sdk/issues/1230)) ([764d665](https://github.com/open-feature/java-sdk/commit/764d6650e659aa93c1da66db348a2eb3641ae92f))
|
||||
* **deps:** update dependency org.simplify4u:slf4j2-mock to v2.4.0 ([#1208](https://github.com/open-feature/java-sdk/issues/1208)) ([a3ced47](https://github.com/open-feature/java-sdk/commit/a3ced47e5dc23badae4f008e5cf4e97c588fdfd4))
|
||||
* **deps:** update github/codeql-action digest to 024283f ([#1211](https://github.com/open-feature/java-sdk/issues/1211)) ([1df5441](https://github.com/open-feature/java-sdk/commit/1df54411b758c67afaf47f103e357cb551e0efca))
|
||||
* **deps:** update github/codeql-action digest to 3096afe ([#1235](https://github.com/open-feature/java-sdk/issues/1235)) ([409fd04](https://github.com/open-feature/java-sdk/commit/409fd042f3921948ef0dabd58d0ef7a4c380b5fb))
|
||||
* **deps:** update github/codeql-action digest to 3aa7135 ([#1186](https://github.com/open-feature/java-sdk/issues/1186)) ([4e3a329](https://github.com/open-feature/java-sdk/commit/4e3a329c406cc72a268f05766290633c67a9aae0))
|
||||
* **deps:** update github/codeql-action digest to 3d3d628 ([#1229](https://github.com/open-feature/java-sdk/issues/1229)) ([a0723ec](https://github.com/open-feature/java-sdk/commit/a0723ec2f886aa834662f2e54bcce5f052262dac))
|
||||
* **deps:** update github/codeql-action digest to 3ef4c08 ([#1205](https://github.com/open-feature/java-sdk/issues/1205)) ([eb4f625](https://github.com/open-feature/java-sdk/commit/eb4f6255615a77c65a79002f1233d1efe5eccd37))
|
||||
* **deps:** update github/codeql-action digest to 48c3e26 ([#1193](https://github.com/open-feature/java-sdk/issues/1193)) ([8621944](https://github.com/open-feature/java-sdk/commit/86219446337e9c73a41b8517b1e26fa044d3bbaa))
|
||||
* **deps:** update github/codeql-action digest to 4dc1519 ([#1209](https://github.com/open-feature/java-sdk/issues/1209)) ([1c21d24](https://github.com/open-feature/java-sdk/commit/1c21d2444b31f61d6d83dfd8f6982f7ad71f708b))
|
||||
* **deps:** update github/codeql-action digest to 5ac2ddd ([#1204](https://github.com/open-feature/java-sdk/issues/1204)) ([3a9fd60](https://github.com/open-feature/java-sdk/commit/3a9fd60fd4a9595a729995a59a0c4ef9625444bc))
|
||||
* **deps:** update github/codeql-action digest to 5cb4249 ([#1210](https://github.com/open-feature/java-sdk/issues/1210)) ([a94bd37](https://github.com/open-feature/java-sdk/commit/a94bd37cff0c6d7b9f535335709d69b79db2c91e))
|
||||
* **deps:** update github/codeql-action digest to 6a38de6 ([#1190](https://github.com/open-feature/java-sdk/issues/1190)) ([f3163df](https://github.com/open-feature/java-sdk/commit/f3163dfbd4b3997a0335699a2472373a846cf710))
|
||||
* **deps:** update github/codeql-action digest to 6e3a010 ([#1214](https://github.com/open-feature/java-sdk/issues/1214)) ([9f37927](https://github.com/open-feature/java-sdk/commit/9f37927eaa60e53d1c7db192ca8e6e117f7f0017))
|
||||
* **deps:** update github/codeql-action digest to 6f9e628 ([#1239](https://github.com/open-feature/java-sdk/issues/1239)) ([baaa78b](https://github.com/open-feature/java-sdk/commit/baaa78b7ec34a3e508fda3ed8c3ea5382f1e18ea))
|
||||
* **deps:** update github/codeql-action digest to 978ed82 ([#1234](https://github.com/open-feature/java-sdk/issues/1234)) ([bb3272d](https://github.com/open-feature/java-sdk/commit/bb3272d36479bde2594fe0bb64cea21d30299931))
|
||||
* **deps:** update github/codeql-action digest to 9f93f47 ([#1191](https://github.com/open-feature/java-sdk/issues/1191)) ([f99de6f](https://github.com/open-feature/java-sdk/commit/f99de6fa55bea093418ecc85ea79e9e30ce03d6b))
|
||||
* **deps:** update github/codeql-action digest to a1695c5 ([#1215](https://github.com/open-feature/java-sdk/issues/1215)) ([6d3bb69](https://github.com/open-feature/java-sdk/commit/6d3bb694204107f21552b48c5f6f056fa37e6cc0))
|
||||
* **deps:** update github/codeql-action digest to a6c8729 ([#1222](https://github.com/open-feature/java-sdk/issues/1222)) ([bbc934c](https://github.com/open-feature/java-sdk/commit/bbc934c6d91af39b9ff384ebd58756d48b00415a))
|
||||
* **deps:** update github/codeql-action digest to acb9cb1 ([#1207](https://github.com/open-feature/java-sdk/issues/1207)) ([21dbd3f](https://github.com/open-feature/java-sdk/commit/21dbd3fc4c29acbb6b74cdb6b82bc5bb4dd5523e))
|
||||
* **deps:** update github/codeql-action digest to af49565 ([#1231](https://github.com/open-feature/java-sdk/issues/1231)) ([4bbaf51](https://github.com/open-feature/java-sdk/commit/4bbaf517536386f53bd92ceaf62eb08fe4859e80))
|
||||
* **deps:** update github/codeql-action digest to b91f43b ([#1184](https://github.com/open-feature/java-sdk/issues/1184)) ([d0309ea](https://github.com/open-feature/java-sdk/commit/d0309eaa6616ef9e9caf8e605895ac82c8f4d780))
|
||||
* **deps:** update github/codeql-action digest to cba5fb5 ([#1221](https://github.com/open-feature/java-sdk/issues/1221)) ([37f0f06](https://github.com/open-feature/java-sdk/commit/37f0f06467b10541755e723ff26144b716a26464))
|
||||
* **deps:** update github/codeql-action digest to cbe1897 ([#1194](https://github.com/open-feature/java-sdk/issues/1194)) ([2dba3a7](https://github.com/open-feature/java-sdk/commit/2dba3a737dac6fefcbb1f56b292cacdca62735b5))
|
||||
* **deps:** update github/codeql-action digest to e782c3a ([#1220](https://github.com/open-feature/java-sdk/issues/1220)) ([45d0656](https://github.com/open-feature/java-sdk/commit/45d065652004ecc0703af3b9c6fbfd2b45e69056))
|
||||
* **deps:** update github/codeql-action digest to ef2fd42 ([#1232](https://github.com/open-feature/java-sdk/issues/1232)) ([b3549a1](https://github.com/open-feature/java-sdk/commit/b3549a1b4aa2bc27c38f66e3a0657b62d8ffc1b4))
|
||||
* **deps:** update github/codeql-action digest to f1c289a ([#1233](https://github.com/open-feature/java-sdk/issues/1233)) ([5b460ea](https://github.com/open-feature/java-sdk/commit/5b460ead7e5f21eb7c86e9ae78740a2e26957420))
|
||||
* **deps:** update github/codeql-action digest to f8e782a ([#1225](https://github.com/open-feature/java-sdk/issues/1225)) ([3227623](https://github.com/open-feature/java-sdk/commit/32276234257f82de98bcb01094c7219611e2c707))
|
||||
|
||||
## [1.12.2](https://github.com/open-feature/java-sdk/compare/v1.12.1...v1.12.2) (2024-10-24)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update junit5 monorepo ([#1171](https://github.com/open-feature/java-sdk/issues/1171)) ([02eed7a](https://github.com/open-feature/java-sdk/commit/02eed7a32c250483348d04925fe6840420b968cb))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* blocking set-provider in test ([d6d284b](https://github.com/open-feature/java-sdk/commit/d6d284b6a3e615ad90505bd183b098b084037616))
|
||||
* **deps:** update actions/cache digest to 6849a64 ([#1174](https://github.com/open-feature/java-sdk/issues/1174)) ([cedad9c](https://github.com/open-feature/java-sdk/commit/cedad9c2c6b6fd5c4b56b30ee5cd471fe4410a40))
|
||||
* **deps:** update actions/checkout digest to 11bd719 ([#1183](https://github.com/open-feature/java-sdk/issues/1183)) ([74958fd](https://github.com/open-feature/java-sdk/commit/74958fd261b0154d156d684e0e01360b8f3ba589))
|
||||
* **deps:** update actions/checkout digest to 163217d ([#1168](https://github.com/open-feature/java-sdk/issues/1168)) ([3f1cfed](https://github.com/open-feature/java-sdk/commit/3f1cfed913537c245284ff59d058982d1ebc8ce3))
|
||||
* **deps:** update actions/setup-java digest to 8df1039 ([#1172](https://github.com/open-feature/java-sdk/issues/1172)) ([a432760](https://github.com/open-feature/java-sdk/commit/a432760fc936b6a1c4ab2ed779c8ab49e6fe1eff))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.6.5 ([#1173](https://github.com/open-feature/java-sdk/issues/1173)) ([b08e8d5](https://github.com/open-feature/java-sdk/commit/b08e8d5537942e8ae8c822f0466f6e18459d2d8d))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.5 ([#1165](https://github.com/open-feature/java-sdk/issues/1165)) ([2d3be26](https://github.com/open-feature/java-sdk/commit/2d3be2617b78d200162ce816e829abda80e130a2))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.7 ([#1179](https://github.com/open-feature/java-sdk/issues/1179)) ([0db0a50](https://github.com/open-feature/java-sdk/commit/0db0a50cf40d62e9880ca68f577c43fe86497532))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.5 ([#1166](https://github.com/open-feature/java-sdk/issues/1166)) ([51a3410](https://github.com/open-feature/java-sdk/commit/51a3410d8e8c85bb0b142e6a64b889795742de86))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.7 ([#1180](https://github.com/open-feature/java-sdk/issues/1180)) ([36620f8](https://github.com/open-feature/java-sdk/commit/36620f84081bb38cc542330ea44e84f6f5754093))
|
||||
* **deps:** update dependency org.codehaus.mojo:exec-maven-plugin to v3.5.0 ([#1175](https://github.com/open-feature/java-sdk/issues/1175)) ([c8c70e2](https://github.com/open-feature/java-sdk/commit/c8c70e23e807681d271ddcb3dc6879dd80cb1c02))
|
||||
* **deps:** update github/codeql-action digest to 0a30541 ([#1170](https://github.com/open-feature/java-sdk/issues/1170)) ([59139a2](https://github.com/open-feature/java-sdk/commit/59139a21867e99e65c9460fba35403efe0aa6f50))
|
||||
* **deps:** update github/codeql-action digest to 467d7e6 ([#1181](https://github.com/open-feature/java-sdk/issues/1181)) ([7a1eb9b](https://github.com/open-feature/java-sdk/commit/7a1eb9b9e94db003e2ada37ecb32cf912eef8766))
|
||||
* **deps:** update github/codeql-action digest to af56b04 ([#1167](https://github.com/open-feature/java-sdk/issues/1167)) ([432ec43](https://github.com/open-feature/java-sdk/commit/432ec438efdbe54e2300dd78db9fff1ce73fd725))
|
||||
* **deps:** update github/codeql-action digest to b35b023 ([#1176](https://github.com/open-feature/java-sdk/issues/1176)) ([9fb469f](https://github.com/open-feature/java-sdk/commit/9fb469f8e8f45afcf55edadcef4d73753d80e0e0))
|
||||
* **deps:** update github/codeql-action digest to b7cdb7f ([#1177](https://github.com/open-feature/java-sdk/issues/1177)) ([a085896](https://github.com/open-feature/java-sdk/commit/a08589664c6464df5443eccdb1b2e9eba84313eb))
|
||||
* **deps:** update github/codeql-action digest to c470063 ([#1163](https://github.com/open-feature/java-sdk/issues/1163)) ([4e39b55](https://github.com/open-feature/java-sdk/commit/4e39b55bda516bb07ffd7452169dc77b1c0e340f))
|
||||
* fix another flaky test ([473a057](https://github.com/open-feature/java-sdk/commit/473a05784cd25dfafdd8f55894b06c8503fb19af))
|
||||
* fix flaky test ([457da96](https://github.com/open-feature/java-sdk/commit/457da96e7ba328f572e086c614b6700e9fd1c8c8))
|
||||
* flaky test ([#1169](https://github.com/open-feature/java-sdk/issues/1169)) ([d6d284b](https://github.com/open-feature/java-sdk/commit/d6d284b6a3e615ad90505bd183b098b084037616))
|
||||
* improve benchmark realism; add more context ([#1182](https://github.com/open-feature/java-sdk/issues/1182)) ([0009e23](https://github.com/open-feature/java-sdk/commit/0009e23c7b38dff78afc7addede41fed16937976))
|
||||
|
||||
|
||||
### 🚀 Performance
|
||||
|
||||
* reduce hashmap allocations ([#1178](https://github.com/open-feature/java-sdk/issues/1178)) ([fd7659a](https://github.com/open-feature/java-sdk/commit/fd7659a46fa7a8c4a04a09217abe7ab228779c7e))
|
||||
|
||||
## [1.12.1](https://github.com/open-feature/java-sdk/compare/v1.12.0...v1.12.1) (2024-10-15)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.20.0 ([#1142](https://github.com/open-feature/java-sdk/issues/1142)) ([e657383](https://github.com/open-feature/java-sdk/commit/e6573838a02df1e917b27a5ae2ad7cef0c4d6b3f))
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.20.1 ([#1153](https://github.com/open-feature/java-sdk/issues/1153)) ([7ccc896](https://github.com/open-feature/java-sdk/commit/7ccc896665b56eddb16f2fd9dd63d489de9d3197))
|
||||
* **deps:** update junit5 monorepo ([#1121](https://github.com/open-feature/java-sdk/issues/1121)) ([91fffb3](https://github.com/open-feature/java-sdk/commit/91fffb35600162454b0600017bfc33b920922455))
|
||||
* **deps:** update junit5 monorepo ([#1141](https://github.com/open-feature/java-sdk/issues/1141)) ([20ea6bd](https://github.com/open-feature/java-sdk/commit/20ea6bd99dba350b41f730c548ce28aa6d7680c2))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/cache digest to 2cdf405 ([#1143](https://github.com/open-feature/java-sdk/issues/1143)) ([a0041c1](https://github.com/open-feature/java-sdk/commit/a0041c10e484aa2ea6bd63efcaac6c4570e1c1a4))
|
||||
* **deps:** update actions/cache digest to 8469c94 ([#1151](https://github.com/open-feature/java-sdk/issues/1151)) ([fdda5e9](https://github.com/open-feature/java-sdk/commit/fdda5e94b615e073dcc103442d61b33cc444f19f))
|
||||
* **deps:** update actions/cache digest to a11fb02 ([#1138](https://github.com/open-feature/java-sdk/issues/1138)) ([43f076a](https://github.com/open-feature/java-sdk/commit/43f076a1251569232b31e98120f29b62628717ac))
|
||||
* **deps:** update actions/checkout digest to 6b42224 ([#1137](https://github.com/open-feature/java-sdk/issues/1137)) ([0c8ff47](https://github.com/open-feature/java-sdk/commit/0c8ff472f2011f4a32ac7fb3252b9362e7ba98e3))
|
||||
* **deps:** update actions/checkout digest to d632683 ([#1122](https://github.com/open-feature/java-sdk/issues/1122)) ([2393924](https://github.com/open-feature/java-sdk/commit/2393924592b9a9cfd44ed4b4be6effeb5e7eca28))
|
||||
* **deps:** update actions/checkout digest to de5a000 ([#1134](https://github.com/open-feature/java-sdk/issues/1134)) ([626f5e1](https://github.com/open-feature/java-sdk/commit/626f5e17c0be58fe5c4b0a286a51fb85ac734c2d))
|
||||
* **deps:** update actions/checkout digest to eef6144 ([#1149](https://github.com/open-feature/java-sdk/issues/1149)) ([16ec4e4](https://github.com/open-feature/java-sdk/commit/16ec4e459b58710664db2d7831611695d6525ff5))
|
||||
* **deps:** update actions/setup-java digest to 292cc14 ([#1124](https://github.com/open-feature/java-sdk/issues/1124)) ([f2c37ea](https://github.com/open-feature/java-sdk/commit/f2c37eacc2982c47408b95839b68f33c6f7f31a5))
|
||||
* **deps:** update actions/setup-java digest to 83a06ff ([#1158](https://github.com/open-feature/java-sdk/issues/1158)) ([98a7ed0](https://github.com/open-feature/java-sdk/commit/98a7ed0727ba160642ad342f1d40e9c69980f4db))
|
||||
* **deps:** update actions/setup-java digest to b36c23c ([#1114](https://github.com/open-feature/java-sdk/issues/1114)) ([5d97803](https://github.com/open-feature/java-sdk/commit/5d9780333a04e507c2eb56253750725d14142b53))
|
||||
* **deps:** update codecov/codecov-action action to v4.6.0 ([#1132](https://github.com/open-feature/java-sdk/issues/1132)) ([f7d6202](https://github.com/open-feature/java-sdk/commit/f7d6202e131f7fd8370831c018787c0aa9deae39))
|
||||
* **deps:** update dependency com.google.guava:guava to v33.3.1-jre ([#1116](https://github.com/open-feature/java-sdk/issues/1116)) ([ce06eee](https://github.com/open-feature/java-sdk/commit/ce06eee9dfe7769f4084baf8a44e18063cbc10fc))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.2 ([#1119](https://github.com/open-feature/java-sdk/issues/1119)) ([b919333](https://github.com/open-feature/java-sdk/commit/b9193338237b7e25d415b8d81718208f885e0a51))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.3 ([#1125](https://github.com/open-feature/java-sdk/issues/1125)) ([5863541](https://github.com/open-feature/java-sdk/commit/58635411bd0f99a9a45d3832d2fee047202befff))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.4 ([#1154](https://github.com/open-feature/java-sdk/issues/1154)) ([4f32aba](https://github.com/open-feature/java-sdk/commit/4f32abaf84059696a63b7aa0d562a0bc6ef8c9f8))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.2 ([#1120](https://github.com/open-feature/java-sdk/issues/1120)) ([c5bace6](https://github.com/open-feature/java-sdk/commit/c5bace6ff258bbe7ed5c23b6abd22892de1cdc19))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.3 ([#1126](https://github.com/open-feature/java-sdk/issues/1126)) ([8765cf3](https://github.com/open-feature/java-sdk/commit/8765cf344087b0e2c76fe8df1d8440eeb85ae209))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.4 ([#1155](https://github.com/open-feature/java-sdk/issues/1155)) ([82a5eb5](https://github.com/open-feature/java-sdk/commit/82a5eb568781c057fcbfc7684d9d6283303d9e0a))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.5.1 ([#1147](https://github.com/open-feature/java-sdk/issues/1147)) ([aaab159](https://github.com/open-feature/java-sdk/commit/aaab1598a177e1596b052c00e054bc77f7f73f58))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.7 ([#1128](https://github.com/open-feature/java-sdk/issues/1128)) ([3816151](https://github.com/open-feature/java-sdk/commit/3816151b876282d5a2aec80e0addc8ee572ea679))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.10.1 ([#1131](https://github.com/open-feature/java-sdk/issues/1131)) ([d4dac27](https://github.com/open-feature/java-sdk/commit/d4dac274eecd65f00f2e79a591ca867eedf454c5))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.1 ([#1144](https://github.com/open-feature/java-sdk/issues/1144)) ([0c0c5f4](https://github.com/open-feature/java-sdk/commit/0c0c5f4ad9c86ed47b38b70c74c6c30dc4266866))
|
||||
* **deps:** update dependency org.cyclonedx:cyclonedx-maven-plugin to v2.8.2 ([#1123](https://github.com/open-feature/java-sdk/issues/1123)) ([db1bc75](https://github.com/open-feature/java-sdk/commit/db1bc75cdeae1147a44e953d267583359b202ef6))
|
||||
* **deps:** update dependency org.cyclonedx:cyclonedx-maven-plugin to v2.9.0 ([#1150](https://github.com/open-feature/java-sdk/issues/1150)) ([6d38b2c](https://github.com/open-feature/java-sdk/commit/6d38b2c5a9d578279a2eeff8a22d39eedb6aaf23))
|
||||
* **deps:** update github/codeql-action digest to 0c3e006 ([#1159](https://github.com/open-feature/java-sdk/issues/1159)) ([a881376](https://github.com/open-feature/java-sdk/commit/a8813760d6cce9124d9b90b5e9affeb87f29cb51))
|
||||
* **deps:** update github/codeql-action digest to 2617ff2 ([#1127](https://github.com/open-feature/java-sdk/issues/1127)) ([93f4feb](https://github.com/open-feature/java-sdk/commit/93f4feb818367fdf1f3f8dd55ac1bdffaf34d5f6))
|
||||
* **deps:** update github/codeql-action digest to 38469af ([#1157](https://github.com/open-feature/java-sdk/issues/1157)) ([20e3a5d](https://github.com/open-feature/java-sdk/commit/20e3a5d3fe6374e762e8439eb198c8968c2066b4))
|
||||
* **deps:** update github/codeql-action digest to 426821d ([#1115](https://github.com/open-feature/java-sdk/issues/1115)) ([a2a55e8](https://github.com/open-feature/java-sdk/commit/a2a55e8f3170172921a132edcb23197a0a03b8a3))
|
||||
* **deps:** update github/codeql-action digest to 46e0c78 ([#1118](https://github.com/open-feature/java-sdk/issues/1118)) ([90c6566](https://github.com/open-feature/java-sdk/commit/90c65666e2ec5e5dcd3cba991202fe867ebcc15d))
|
||||
* **deps:** update github/codeql-action digest to 5636274 ([#1161](https://github.com/open-feature/java-sdk/issues/1161)) ([b144763](https://github.com/open-feature/java-sdk/commit/b1447632992c1c474bb7edfad632f85a7e0c21a9))
|
||||
* **deps:** update github/codeql-action digest to 56d1975 ([#1145](https://github.com/open-feature/java-sdk/issues/1145)) ([2489e40](https://github.com/open-feature/java-sdk/commit/2489e40c290421040a8ae21ee1435055dbcd3e24))
|
||||
* **deps:** update github/codeql-action digest to 572cc52 ([#1148](https://github.com/open-feature/java-sdk/issues/1148)) ([03e6604](https://github.com/open-feature/java-sdk/commit/03e66049601c64fec4c8b516ec5557a3f82ab828))
|
||||
* **deps:** update github/codeql-action digest to 7cf65a5 ([#1140](https://github.com/open-feature/java-sdk/issues/1140)) ([9eb64a7](https://github.com/open-feature/java-sdk/commit/9eb64a747151f791d740f986c9dd358cbb813acc))
|
||||
* **deps:** update github/codeql-action digest to 8aba5f2 ([#1136](https://github.com/open-feature/java-sdk/issues/1136)) ([16e1dec](https://github.com/open-feature/java-sdk/commit/16e1dec928bf9252339bcff433cd3cb7435554d9))
|
||||
* **deps:** update github/codeql-action digest to 8b33300 ([#1139](https://github.com/open-feature/java-sdk/issues/1139)) ([1f2c5a1](https://github.com/open-feature/java-sdk/commit/1f2c5a1b2a669c65364e8e24e0824de791f4a4b4))
|
||||
* **deps:** update github/codeql-action digest to 9d1e406 ([#1152](https://github.com/open-feature/java-sdk/issues/1152)) ([e982216](https://github.com/open-feature/java-sdk/commit/e982216f705763bf1cb2638e078e54590fb4c949))
|
||||
* **deps:** update github/codeql-action digest to a196a71 ([#1133](https://github.com/open-feature/java-sdk/issues/1133)) ([c8722a2](https://github.com/open-feature/java-sdk/commit/c8722a2ac63c4aef7551ec591a1879bb60b9ad26))
|
||||
* **deps:** update github/codeql-action digest to c4d433c ([#1135](https://github.com/open-feature/java-sdk/issues/1135)) ([26659a3](https://github.com/open-feature/java-sdk/commit/26659a3eed251e6e38ce892ca8f11945ca5add90))
|
||||
* **deps:** update github/codeql-action digest to cf5b0a9 ([#1130](https://github.com/open-feature/java-sdk/issues/1130)) ([02f4ec1](https://github.com/open-feature/java-sdk/commit/02f4ec1061b82a51995389c5dad9c1abc0d35862))
|
||||
* **deps:** update github/codeql-action digest to ea2cd92 ([#1160](https://github.com/open-feature/java-sdk/issues/1160)) ([f28cefe](https://github.com/open-feature/java-sdk/commit/f28cefe3b1ea9daffccb87ff55772a2e8f7d0e81))
|
||||
|
||||
|
||||
### 🚀 Performance
|
||||
|
||||
* add heap benchmark and reduce allocations ([#1156](https://github.com/open-feature/java-sdk/issues/1156)) ([9008818](https://github.com/open-feature/java-sdk/commit/90088188c90da9fcca4e50328405e56f9ae17dde))
|
||||
|
||||
## [1.12.0](https://github.com/open-feature/java-sdk/compare/v1.11.0...v1.12.0) (2024-09-23)
|
||||
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
* make provider interface "stateless"; SDK maintains provider state ([#1096](https://github.com/open-feature/java-sdk/issues/1096)) ([1b1e527](https://github.com/open-feature/java-sdk/commit/1b1e527e780128c9aa3c0686427a8fe8856800b4))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.6.4 ([#1113](https://github.com/open-feature/java-sdk/issues/1113)) ([dd8ba81](https://github.com/open-feature/java-sdk/commit/dd8ba81f1286a622aec2611f023d03a56a155e89))
|
||||
* **deps:** update github/codeql-action digest to 323f5ef ([#1111](https://github.com/open-feature/java-sdk/issues/1111)) ([52e6d2b](https://github.com/open-feature/java-sdk/commit/52e6d2b0ee17124ef2a742fc872a939fde977a27))
|
||||
|
||||
## [1.11.0](https://github.com/open-feature/java-sdk/compare/v1.10.0...v1.11.0) (2024-09-20)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.19.0 ([#1110](https://github.com/open-feature/java-sdk/issues/1110)) ([2412f29](https://github.com/open-feature/java-sdk/commit/2412f296b5db43c07dc807390070379e7781dbb3))
|
||||
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
* error resolution flow control without exceptions ([#1095](https://github.com/open-feature/java-sdk/issues/1095)) ([6fc0b90](https://github.com/open-feature/java-sdk/commit/6fc0b9061079e50cbab52c951149cf600a922671))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/checkout digest to 6d193bf ([#1091](https://github.com/open-feature/java-sdk/issues/1091)) ([9f6a40e](https://github.com/open-feature/java-sdk/commit/9f6a40ec9ba490edf13adc5501a8cb2b93c32447))
|
||||
* **deps:** update actions/checkout digest to b684943 ([#1088](https://github.com/open-feature/java-sdk/issues/1088)) ([7e0c70f](https://github.com/open-feature/java-sdk/commit/7e0c70f7c547b6eb14f30ba4e77657a317161c1f))
|
||||
* **deps:** update actions/setup-java digest to 0a40ce6 ([#1107](https://github.com/open-feature/java-sdk/issues/1107)) ([37b56ac](https://github.com/open-feature/java-sdk/commit/37b56ac2dad3c24ac1d898a253e936aa2e3d49eb))
|
||||
* **deps:** update actions/setup-java digest to 2dfa201 ([#1094](https://github.com/open-feature/java-sdk/issues/1094)) ([082f574](https://github.com/open-feature/java-sdk/commit/082f5746c84f1bb4ff54cae4f525949f29e7b9c4))
|
||||
* **deps:** update actions/setup-java digest to 40b9536 ([#1109](https://github.com/open-feature/java-sdk/issues/1109)) ([244f216](https://github.com/open-feature/java-sdk/commit/244f216582eae071885a950712115ce8b1ad0c19))
|
||||
* **deps:** update actions/setup-java digest to 7467385 ([#1092](https://github.com/open-feature/java-sdk/issues/1092)) ([58ead7f](https://github.com/open-feature/java-sdk/commit/58ead7fa9153a53ec530e349f16f9e5e183aa0fb))
|
||||
* **deps:** update actions/setup-java digest to bcfbca5 ([#1100](https://github.com/open-feature/java-sdk/issues/1100)) ([c68f78e](https://github.com/open-feature/java-sdk/commit/c68f78e17b6125d74644a5735f9d58348edcc383))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.6 ([#1103](https://github.com/open-feature/java-sdk/issues/1103)) ([29901b8](https://github.com/open-feature/java-sdk/commit/29901b87ea93757abe5f5d7a8afc6fc4555aef5c))
|
||||
* **deps:** update github/codeql-action digest to 4a01ec7 ([#1101](https://github.com/open-feature/java-sdk/issues/1101)) ([b80fd6d](https://github.com/open-feature/java-sdk/commit/b80fd6d307dee87d8b8f148c954c33b8ff6efae2))
|
||||
* **deps:** update github/codeql-action digest to 5618c9f ([#1102](https://github.com/open-feature/java-sdk/issues/1102)) ([d1478c0](https://github.com/open-feature/java-sdk/commit/d1478c001a8e88c358d6743ac3d7c9b5523a893e))
|
||||
* **deps:** update github/codeql-action digest to 64431c6 ([#1106](https://github.com/open-feature/java-sdk/issues/1106)) ([ce19ac9](https://github.com/open-feature/java-sdk/commit/ce19ac91f62689a0e0e02e53538e1035bf95387f))
|
||||
* **deps:** update github/codeql-action digest to 782de45 ([#1104](https://github.com/open-feature/java-sdk/issues/1104)) ([7cb8908](https://github.com/open-feature/java-sdk/commit/7cb89087daa2809d3fd8447388e58e4f73c975b3))
|
||||
* **deps:** update github/codeql-action digest to 799e477 ([#1108](https://github.com/open-feature/java-sdk/issues/1108)) ([17a58ef](https://github.com/open-feature/java-sdk/commit/17a58efc7e0244c0db77e77a78f6d0daf948028f))
|
||||
* **deps:** update github/codeql-action digest to 8fd294e ([#1097](https://github.com/open-feature/java-sdk/issues/1097)) ([6408261](https://github.com/open-feature/java-sdk/commit/64082617fade3fa7d647302cc0c5b698f7038d81))
|
||||
* **deps:** update github/codeql-action digest to 9b41ced ([#1089](https://github.com/open-feature/java-sdk/issues/1089)) ([870fc27](https://github.com/open-feature/java-sdk/commit/870fc27ed7a30cb011080127f7d040c1a3bb209b))
|
||||
* **deps:** update github/codeql-action digest to cb28816 ([#1105](https://github.com/open-feature/java-sdk/issues/1105)) ([9d69ebd](https://github.com/open-feature/java-sdk/commit/9d69ebd94a161e6477f2b4f1f5edd0b79f178852))
|
||||
* **deps:** update github/codeql-action digest to d8b1697 ([#1093](https://github.com/open-feature/java-sdk/issues/1093)) ([d60593f](https://github.com/open-feature/java-sdk/commit/d60593fa11f39c6587e280633cf6e15965c0960f))
|
||||
* **deps:** update github/codeql-action digest to e817992 ([#1099](https://github.com/open-feature/java-sdk/issues/1099)) ([caec6e3](https://github.com/open-feature/java-sdk/commit/caec6e35e9da3ad88a8de105ca170137f42b907c))
|
||||
|
||||
## [1.10.0](https://github.com/open-feature/java-sdk/compare/v1.9.1...v1.10.0) (2024-09-05)
|
||||
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
* add logging hook, rm logging from evaluation ([#1084](https://github.com/open-feature/java-sdk/issues/1084)) ([037826f](https://github.com/open-feature/java-sdk/commit/037826fe1b1c7fecdac95b45bfcdef5d66d49f60))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/checkout digest to 2d7d9f7 ([#1082](https://github.com/open-feature/java-sdk/issues/1082)) ([9196599](https://github.com/open-feature/java-sdk/commit/9196599f30388dd38b8fb11052772c01f16ed481))
|
||||
* **deps:** update actions/setup-java digest to 8e04ddf ([#1080](https://github.com/open-feature/java-sdk/issues/1080)) ([0cc5ca1](https://github.com/open-feature/java-sdk/commit/0cc5ca1397d33cd8802cf40d19130d03c84da340))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.6.3 ([#1087](https://github.com/open-feature/java-sdk/issues/1087)) ([78e3371](https://github.com/open-feature/java-sdk/commit/78e3371c0578984b46d70328a8940425786cae4d))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.0 ([#1063](https://github.com/open-feature/java-sdk/issues/1063)) ([7fea9b1](https://github.com/open-feature/java-sdk/commit/7fea9b106c1cf3ffe4ce7d5a9448a179d7041ed0))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy to v1.15.1 ([#1078](https://github.com/open-feature/java-sdk/issues/1078)) ([9836006](https://github.com/open-feature/java-sdk/commit/98360061a889713fa4b67bd1d0721e5496a18714))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.0 ([#1064](https://github.com/open-feature/java-sdk/issues/1064)) ([dd53021](https://github.com/open-feature/java-sdk/commit/dd53021153a192370a0cbf56fbccd42eeb870043))
|
||||
* **deps:** update dependency net.bytebuddy:byte-buddy-agent to v1.15.1 ([#1079](https://github.com/open-feature/java-sdk/issues/1079)) ([a3285df](https://github.com/open-feature/java-sdk/commit/a3285df729aaa2c89941bfc180cf736228ab10ef))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.5.0 ([#1073](https://github.com/open-feature/java-sdk/issues/1073)) ([c845035](https://github.com/open-feature/java-sdk/commit/c8450358c02d942f7772ccac6c740078f7594a51))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.10.0 ([#1072](https://github.com/open-feature/java-sdk/issues/1072)) ([3eed950](https://github.com/open-feature/java-sdk/commit/3eed950d3c296888acc0abe486d6c34d57170141))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-pmd-plugin to v3.25.0 ([#1074](https://github.com/open-feature/java-sdk/issues/1074)) ([5ee3851](https://github.com/open-feature/java-sdk/commit/5ee38510a87d089f4440657569fb34cc3f133415))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.0 ([#1075](https://github.com/open-feature/java-sdk/issues/1075)) ([b772119](https://github.com/open-feature/java-sdk/commit/b772119977b8731668d809f50cacaa66f83d53b7))
|
||||
* **deps:** update github/codeql-action digest to 7233ec5 ([#1076](https://github.com/open-feature/java-sdk/issues/1076)) ([eb5526d](https://github.com/open-feature/java-sdk/commit/eb5526d75fb94c9b57b5124982e9b3510d654324))
|
||||
* **deps:** update github/codeql-action digest to 7e27807 ([#1067](https://github.com/open-feature/java-sdk/issues/1067)) ([a07eb67](https://github.com/open-feature/java-sdk/commit/a07eb6786546066b0e416c9e072db770833d3dbd))
|
||||
* **deps:** update github/codeql-action digest to 821ab42 ([#1081](https://github.com/open-feature/java-sdk/issues/1081)) ([a4d428c](https://github.com/open-feature/java-sdk/commit/a4d428c83c0d243d85b6bf82ffd15248d3dab570))
|
||||
* **deps:** update github/codeql-action digest to 864b979 ([#1070](https://github.com/open-feature/java-sdk/issues/1070)) ([ee6d8b0](https://github.com/open-feature/java-sdk/commit/ee6d8b094af3dcf83aa08f934035888bc0311c37))
|
||||
* **deps:** update github/codeql-action digest to 889597e ([#1086](https://github.com/open-feature/java-sdk/issues/1086)) ([dd7696f](https://github.com/open-feature/java-sdk/commit/dd7696f473a23f789098ca3103b474baa274a233))
|
||||
* **deps:** update github/codeql-action digest to a895f2e ([#1068](https://github.com/open-feature/java-sdk/issues/1068)) ([ea59e7f](https://github.com/open-feature/java-sdk/commit/ea59e7fa587768832f45a836d4da694a8ebcfde6))
|
||||
* **deps:** update github/codeql-action digest to b43ac1c ([#1077](https://github.com/open-feature/java-sdk/issues/1077)) ([3f5294c](https://github.com/open-feature/java-sdk/commit/3f5294c734278d6ce13bbfae9731c0b46e3e9e15))
|
||||
* **deps:** update github/codeql-action digest to b4a8631 ([#1083](https://github.com/open-feature/java-sdk/issues/1083)) ([90648d1](https://github.com/open-feature/java-sdk/commit/90648d1c9d9adffa85442b39bd0197ac7e032a51))
|
||||
* **deps:** update github/codeql-action digest to b8efe4d ([#1071](https://github.com/open-feature/java-sdk/issues/1071)) ([5668987](https://github.com/open-feature/java-sdk/commit/5668987274952693cad77bc37fa054ee1ed603fe))
|
||||
* **deps:** update github/codeql-action digest to d36c7aa ([#1069](https://github.com/open-feature/java-sdk/issues/1069)) ([0e048c1](https://github.com/open-feature/java-sdk/commit/0e048c1ff5eae3ec121c2219e8ce9685264135bb))
|
||||
* various non-functional refactors ([#1066](https://github.com/open-feature/java-sdk/issues/1066)) ([35d4cc2](https://github.com/open-feature/java-sdk/commit/35d4cc23c85a24f2d55992cb40b357e450f8e9b7))
|
||||
|
||||
## [1.9.1](https://github.com/open-feature/java-sdk/compare/v1.9.0...v1.9.1) (2024-08-22)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.18.1 ([#1011](https://github.com/open-feature/java-sdk/issues/1011)) ([91fa8cf](https://github.com/open-feature/java-sdk/commit/91fa8cf7d63374cd67d4c02d291467da379297cf))
|
||||
* **deps:** update dependency org.slf4j:slf4j-api to v2.0.14 ([#1033](https://github.com/open-feature/java-sdk/issues/1033)) ([4ec155d](https://github.com/open-feature/java-sdk/commit/4ec155d91b4cc637d1d447ea87308401a5fd7d87))
|
||||
* **deps:** update dependency org.slf4j:slf4j-api to v2.0.15 ([#1036](https://github.com/open-feature/java-sdk/issues/1036)) ([fed9394](https://github.com/open-feature/java-sdk/commit/fed93942b88e0042c50801e8fa193cd156487d4c))
|
||||
* **deps:** update dependency org.slf4j:slf4j-api to v2.0.16 ([#1039](https://github.com/open-feature/java-sdk/issues/1039)) ([beba1bd](https://github.com/open-feature/java-sdk/commit/beba1bd8d6c6d7f0d7d7c947777ad9e5ee0e4649))
|
||||
* **deps:** update junit5 monorepo ([#1045](https://github.com/open-feature/java-sdk/issues/1045)) ([5e77f8a](https://github.com/open-feature/java-sdk/commit/5e77f8ad337fa3230a71db7d722cce01a50f654b))
|
||||
* Pin byte-buddy(-agent) version to 1.14.19 to workaround Mockito issue ([#1060](https://github.com/open-feature/java-sdk/issues/1060)) ([32340a3](https://github.com/open-feature/java-sdk/commit/32340a3e0e11ce49c4405658f40568b04926264e))
|
||||
* updated context not passed to all hooks ([#1049](https://github.com/open-feature/java-sdk/issues/1049)) ([dbf967a](https://github.com/open-feature/java-sdk/commit/dbf967a860d38f4b76bb6d47b6507e87669fa59a))
|
||||
* Use ConcurrentHashMap for InMemoryProvider ([#1057](https://github.com/open-feature/java-sdk/issues/1057)) ([b7ed041](https://github.com/open-feature/java-sdk/commit/b7ed041eed19a7a872c2c73f18163f616ec146c2))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* **deps:** update actions/cache digest to 40c3b67 ([#1026](https://github.com/open-feature/java-sdk/issues/1026)) ([41128b8](https://github.com/open-feature/java-sdk/commit/41128b86fb55d060aed7af836ef9f2365d033446))
|
||||
* **deps:** update actions/cache digest to 4a28cbc ([#1022](https://github.com/open-feature/java-sdk/issues/1022)) ([865c3bb](https://github.com/open-feature/java-sdk/commit/865c3bb17a2fb5a8ab5832cf32b806b8b4a5660e))
|
||||
* **deps:** update actions/cache digest to 57b8e40 ([#1030](https://github.com/open-feature/java-sdk/issues/1030)) ([6990e21](https://github.com/open-feature/java-sdk/commit/6990e21b47befdb4c9b2431c63ddb6db6ccecff7))
|
||||
* **deps:** update actions/cache digest to 81382a7 ([#1044](https://github.com/open-feature/java-sdk/issues/1044)) ([d746dc0](https://github.com/open-feature/java-sdk/commit/d746dc0a11cd837fe9a1472b3cc2ef47fcb616a8))
|
||||
* **deps:** update actions/checkout digest to 9a9194f ([#1023](https://github.com/open-feature/java-sdk/issues/1023)) ([326a10b](https://github.com/open-feature/java-sdk/commit/326a10ba0160627387fff20c52c50250bb176a3a))
|
||||
* **deps:** update actions/setup-java digest to 67fbd72 ([#1037](https://github.com/open-feature/java-sdk/issues/1037)) ([b4f0550](https://github.com/open-feature/java-sdk/commit/b4f0550a2b9530dc23603f7e5aedf19a1ce0b08a))
|
||||
* **deps:** update actions/setup-java digest to 6a0805f ([#1027](https://github.com/open-feature/java-sdk/issues/1027)) ([0968674](https://github.com/open-feature/java-sdk/commit/09686741ad174f3467e7d8b8adfeef13f0afbcbf))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.6.2 ([#999](https://github.com/open-feature/java-sdk/issues/999)) ([d0b3b35](https://github.com/open-feature/java-sdk/commit/d0b3b3598115e55cda334a6c7ced72b6ae28a063))
|
||||
* **deps:** update dependency com.google.guava:guava to v33.3.0-jre ([#1050](https://github.com/open-feature/java-sdk/issues/1050)) ([a36d2ab](https://github.com/open-feature/java-sdk/commit/a36d2ab111b3f8e0f88291ea7baec83d082d233c))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-checkstyle-plugin to v3.5.0 ([#1062](https://github.com/open-feature/java-sdk/issues/1062)) ([8370d42](https://github.com/open-feature/java-sdk/commit/8370d4209de8181bc5d3253b874f296089c110f6))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-dependency-plugin to v3.8.0 ([#1061](https://github.com/open-feature/java-sdk/issues/1061)) ([a81957f](https://github.com/open-feature/java-sdk/commit/a81957ff560c46c5dfb5e38b2f374878e7f5df31))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.3.1 ([#1004](https://github.com/open-feature/java-sdk/issues/1004)) ([7ae703e](https://github.com/open-feature/java-sdk/commit/7ae703e1da581d036c0f970b6712c2fb611bb805))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.4.0 ([#1051](https://github.com/open-feature/java-sdk/issues/1051)) ([a1ceb1f](https://github.com/open-feature/java-sdk/commit/a1ceb1fbbfb428c6ea05b68a303640d6dd895713))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-gpg-plugin to v3.2.5 ([#1040](https://github.com/open-feature/java-sdk/issues/1040)) ([b215dec](https://github.com/open-feature/java-sdk/commit/b215dec8b8ea7f87b515404fc14c740370cc67d0))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.8.0 ([#1013](https://github.com/open-feature/java-sdk/issues/1013)) ([3d0cd62](https://github.com/open-feature/java-sdk/commit/3d0cd62c9838ef4bd354cb84bcf43518589ae3a7))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-pmd-plugin to v3.24.0 ([#1009](https://github.com/open-feature/java-sdk/issues/1009)) ([efbb69a](https://github.com/open-feature/java-sdk/commit/efbb69a998f20e559b1b610cc190bdbd19ea8100))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.3.1 ([#1005](https://github.com/open-feature/java-sdk/issues/1005)) ([e8568a8](https://github.com/open-feature/java-sdk/commit/e8568a8ea2c130be581a310be2214900eddf9d8f))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.4.0 ([#1052](https://github.com/open-feature/java-sdk/issues/1052)) ([13dd70f](https://github.com/open-feature/java-sdk/commit/13dd70f8472be2d0648f4880480c38f4aa51ec04))
|
||||
* **deps:** update dependency org.assertj:assertj-core to v3.26.3 ([#1002](https://github.com/open-feature/java-sdk/issues/1002)) ([2f5deb1](https://github.com/open-feature/java-sdk/commit/2f5deb1a3a578357bb8b965bc7ad0e61f5a8a782))
|
||||
* **deps:** update dependency org.awaitility:awaitility to v4.2.2 ([#1035](https://github.com/open-feature/java-sdk/issues/1035)) ([4591d3f](https://github.com/open-feature/java-sdk/commit/4591d3f1da330ba3631618b96576f48def6f59e0))
|
||||
* **deps:** update dependency org.codehaus.mojo:exec-maven-plugin to v3.4.0 ([#1034](https://github.com/open-feature/java-sdk/issues/1034)) ([ccabb18](https://github.com/open-feature/java-sdk/commit/ccabb1856cd697d54a227d3562278d03088b3aeb))
|
||||
* **deps:** update dependency org.codehaus.mojo:exec-maven-plugin to v3.4.1 ([#1042](https://github.com/open-feature/java-sdk/issues/1042)) ([37121e9](https://github.com/open-feature/java-sdk/commit/37121e9939338e83102fa004731efc209a8d32c4))
|
||||
* **deps:** update dependency org.cyclonedx:cyclonedx-maven-plugin to v2.8.1 ([#1029](https://github.com/open-feature/java-sdk/issues/1029)) ([89cb747](https://github.com/open-feature/java-sdk/commit/89cb7479f48b9f930b70e992aa94acd1ad9346a9))
|
||||
* **deps:** update github/codeql-action digest to 064a406 ([#1000](https://github.com/open-feature/java-sdk/issues/1000)) ([42d2d77](https://github.com/open-feature/java-sdk/commit/42d2d776a8e475bb2247d616cfc07bac896cf089))
|
||||
* **deps:** update github/codeql-action digest to 0d5982a ([#1043](https://github.com/open-feature/java-sdk/issues/1043)) ([f1ea405](https://github.com/open-feature/java-sdk/commit/f1ea4057fc9bccd4e32ac042060f967f934b0090))
|
||||
* **deps:** update github/codeql-action digest to 0e346f2 ([#1014](https://github.com/open-feature/java-sdk/issues/1014)) ([f1b0eb1](https://github.com/open-feature/java-sdk/commit/f1b0eb154dcbd1a02158b457a1bf848eb3040925))
|
||||
* **deps:** update github/codeql-action digest to 16639b4 ([#1024](https://github.com/open-feature/java-sdk/issues/1024)) ([d23a911](https://github.com/open-feature/java-sdk/commit/d23a9115c8f2fa43d05dde37b2aac88c872b0b8c))
|
||||
* **deps:** update github/codeql-action digest to 1b214db ([#1018](https://github.com/open-feature/java-sdk/issues/1018)) ([aa7f8b9](https://github.com/open-feature/java-sdk/commit/aa7f8b97f0464d36d3a87574915fe95901b612c5))
|
||||
* **deps:** update github/codeql-action digest to 202b3b9 ([#1056](https://github.com/open-feature/java-sdk/issues/1056)) ([61d821a](https://github.com/open-feature/java-sdk/commit/61d821ae8a2f64dbc20aa97002e973a423e3ccf7))
|
||||
* **deps:** update github/codeql-action digest to 25ad3c8 ([#1038](https://github.com/open-feature/java-sdk/issues/1038)) ([75b9acd](https://github.com/open-feature/java-sdk/commit/75b9acd79110bba199b84d262a7bf820fc515153))
|
||||
* **deps:** update github/codeql-action digest to 270a29d ([#1010](https://github.com/open-feature/java-sdk/issues/1010)) ([1d31726](https://github.com/open-feature/java-sdk/commit/1d31726e574ae09aeccb0365f6797e78187eb6ce))
|
||||
* **deps:** update github/codeql-action digest to 339aada ([#1053](https://github.com/open-feature/java-sdk/issues/1053)) ([aed4ea2](https://github.com/open-feature/java-sdk/commit/aed4ea21d6735c1aa4d2b16c2ec1d95b2de57672))
|
||||
* **deps:** update github/codeql-action digest to 44534b7 ([#1012](https://github.com/open-feature/java-sdk/issues/1012)) ([eca299b](https://github.com/open-feature/java-sdk/commit/eca299b3ad05dc198a91b29cac27c5df6a94eb3e))
|
||||
* **deps:** update github/codeql-action digest to 4b1d7da ([#1020](https://github.com/open-feature/java-sdk/issues/1020)) ([7db6d8a](https://github.com/open-feature/java-sdk/commit/7db6d8a3d3fb1dc17cb85740f0666601252a3c6e))
|
||||
* **deps:** update github/codeql-action digest to 512e306 ([#1055](https://github.com/open-feature/java-sdk/issues/1055)) ([7cac198](https://github.com/open-feature/java-sdk/commit/7cac1984f84e2aea631e98cb605c768123c870be))
|
||||
* **deps:** update github/codeql-action digest to 5c02493 ([#1032](https://github.com/open-feature/java-sdk/issues/1032)) ([1ed7fc1](https://github.com/open-feature/java-sdk/commit/1ed7fc15774af26b7c73238dc35b39a7c20ef129))
|
||||
* **deps:** update github/codeql-action digest to 5c681ef ([#1048](https://github.com/open-feature/java-sdk/issues/1048)) ([00bc060](https://github.com/open-feature/java-sdk/commit/00bc0609eb270e15129a3ebadb8671e61603b865))
|
||||
* **deps:** update github/codeql-action digest to 5cdd182 ([#1025](https://github.com/open-feature/java-sdk/issues/1025)) ([c574ec5](https://github.com/open-feature/java-sdk/commit/c574ec5c777017b2cdae770fbf35def4b6be1b55))
|
||||
* **deps:** update github/codeql-action digest to 6e04d51 ([#1001](https://github.com/open-feature/java-sdk/issues/1001)) ([145dfc7](https://github.com/open-feature/java-sdk/commit/145dfc70c276c0e9d3fe28f582ad5385a84ec0f6))
|
||||
* **deps:** update github/codeql-action digest to 79e9a50 ([#995](https://github.com/open-feature/java-sdk/issues/995)) ([e2c70d9](https://github.com/open-feature/java-sdk/commit/e2c70d9f0b4768ccbe9796cb14e99a92e5ba3dbc))
|
||||
* **deps:** update github/codeql-action digest to 7adf9ac ([#998](https://github.com/open-feature/java-sdk/issues/998)) ([62f95b6](https://github.com/open-feature/java-sdk/commit/62f95b651bb7bc18f984e42264900f2b486bf6bb))
|
||||
* **deps:** update github/codeql-action digest to 857f661 ([#1007](https://github.com/open-feature/java-sdk/issues/1007)) ([aab84b8](https://github.com/open-feature/java-sdk/commit/aab84b80af81a280d5729455048202090de7f7da))
|
||||
* **deps:** update github/codeql-action digest to 9ab7277 ([#1006](https://github.com/open-feature/java-sdk/issues/1006)) ([2bb58d6](https://github.com/open-feature/java-sdk/commit/2bb58d6e1b160848e7cb92394ae9f1b98f091b34))
|
||||
* **deps:** update github/codeql-action digest to 9c646c2 ([#1028](https://github.com/open-feature/java-sdk/issues/1028)) ([cd4c823](https://github.com/open-feature/java-sdk/commit/cd4c8239cd8c70dd8cdbc5398bfcb74668a65499))
|
||||
* **deps:** update github/codeql-action digest to a93f8c2 ([#1046](https://github.com/open-feature/java-sdk/issues/1046)) ([2934195](https://github.com/open-feature/java-sdk/commit/2934195a8f81b66c5b1ae45f0d7ec2252f830c24))
|
||||
* **deps:** update github/codeql-action digest to aa96d09 ([#1021](https://github.com/open-feature/java-sdk/issues/1021)) ([e57eafd](https://github.com/open-feature/java-sdk/commit/e57eafd86d9e333d70d027a64d7b83d4f2ce4f9f))
|
||||
* **deps:** update github/codeql-action digest to b400d0f ([#1016](https://github.com/open-feature/java-sdk/issues/1016)) ([5db43ad](https://github.com/open-feature/java-sdk/commit/5db43ad1aae4581d92f18eb8b209c701af55b1a5))
|
||||
* **deps:** update github/codeql-action digest to be825d5 ([#1003](https://github.com/open-feature/java-sdk/issues/1003)) ([f3d9a55](https://github.com/open-feature/java-sdk/commit/f3d9a55eb7c3955bc3dbf2c9db5f494749e2c890))
|
||||
* **deps:** update github/codeql-action digest to c24926b ([#1031](https://github.com/open-feature/java-sdk/issues/1031)) ([22435a6](https://github.com/open-feature/java-sdk/commit/22435a694a98022998d1b75a0cbee59caceccf15))
|
||||
* **deps:** update github/codeql-action digest to c2585ec ([#1008](https://github.com/open-feature/java-sdk/issues/1008)) ([9cc9241](https://github.com/open-feature/java-sdk/commit/9cc9241b014edb8ac25aa830ab250009d4bc506a))
|
||||
* **deps:** update github/codeql-action digest to d620faa ([#1041](https://github.com/open-feature/java-sdk/issues/1041)) ([69db287](https://github.com/open-feature/java-sdk/commit/69db2870071bfc5b307a0b5f6df27dc7f77daa26))
|
||||
* **deps:** update github/codeql-action digest to ee4ad8b ([#997](https://github.com/open-feature/java-sdk/issues/997)) ([fc40209](https://github.com/open-feature/java-sdk/commit/fc40209edcffc063a474aec7bfe9a880e0966750))
|
||||
* **deps:** update github/codeql-action digest to f67c9cd ([#1017](https://github.com/open-feature/java-sdk/issues/1017)) ([baa1331](https://github.com/open-feature/java-sdk/commit/baa13313e8cc10ab4f9f6dc6a216326dfcdc74b2))
|
||||
* **deps:** update github/codeql-action digest to f8e94f9 ([#1019](https://github.com/open-feature/java-sdk/issues/1019)) ([cf760e4](https://github.com/open-feature/java-sdk/commit/cf760e4cc4227b7bac4c4ce5192d06ed39a7783b))
|
||||
* **deps:** update github/codeql-action digest to fd5fa13 ([#1058](https://github.com/open-feature/java-sdk/issues/1058)) ([b0f915b](https://github.com/open-feature/java-sdk/commit/b0f915bb09d294e8b399941974b546cbd3bff187))
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
* Small typo sonartype vs sonatype ([#989](https://github.com/open-feature/java-sdk/issues/989)) ([7bff3ee](https://github.com/open-feature/java-sdk/commit/7bff3eebe624c9fecd705dd5fdd51d9483cb4643))
|
||||
|
||||
## [1.9.0](https://github.com/open-feature/java-sdk/compare/v1.8.0...v1.9.0) (2024-06-28)
|
||||
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
* **deps:** update dependency io.cucumber:cucumber-bom to v7.18.0 ([#944](https://github.com/open-feature/java-sdk/issues/944)) ([bdc19b2](https://github.com/open-feature/java-sdk/commit/bdc19b2cc07dfbad1093914933b52d405d9941f7))
|
||||
* **deps:** update dependency org.projectlombok:lombok to v1.18.34 ([#993](https://github.com/open-feature/java-sdk/issues/993)) ([44b4b35](https://github.com/open-feature/java-sdk/commit/44b4b354311deee266b6b4f2a911293a0ec8f049))
|
||||
* **deps:** update junit5 monorepo ([#990](https://github.com/open-feature/java-sdk/issues/990)) ([a2c04c1](https://github.com/open-feature/java-sdk/commit/a2c04c1b23f18dbe45bb206749ddcf996e277dca))
|
||||
* PMD warnings with new version ([#936](https://github.com/open-feature/java-sdk/issues/936)) ([1a46aea](https://github.com/open-feature/java-sdk/commit/1a46aea2422e6841a7909c01b8568450360477d7))
|
||||
* run error hook when provider returns error code ([#951](https://github.com/open-feature/java-sdk/issues/951)) ([dbfeb72](https://github.com/open-feature/java-sdk/commit/dbfeb72bc5c1cda089384cf15f034c92f9d795c5))
|
||||
|
||||
|
||||
### ✨ New Features
|
||||
|
||||
* implement domain scoping ([#934](https://github.com/open-feature/java-sdk/issues/934)) ([5c0aaaa](https://github.com/open-feature/java-sdk/commit/5c0aaaa8bc939412bf8f6ca21f47cd7a7f504ada))
|
||||
|
||||
|
||||
### 🧹 Chore
|
||||
|
||||
* Adding information needed for spec-compliance tooling ([#900](https://github.com/open-feature/java-sdk/issues/900)) ([e65b2a0](https://github.com/open-feature/java-sdk/commit/e65b2a0ecbb25c5bcba1006195b34112f2e53808))
|
||||
* **deps:** update actions/checkout digest to 692973e ([#972](https://github.com/open-feature/java-sdk/issues/972)) ([c3eb16c](https://github.com/open-feature/java-sdk/commit/c3eb16cd75e168c317307be2d65ba4a2bad2bea7))
|
||||
* **deps:** update actions/checkout digest to a5ac7e5 ([#941](https://github.com/open-feature/java-sdk/issues/941)) ([08567f4](https://github.com/open-feature/java-sdk/commit/08567f43c85236d32101a608adad1586cb0bd952))
|
||||
* **deps:** update actions/checkout digest to b80ff79 ([#945](https://github.com/open-feature/java-sdk/issues/945)) ([015961b](https://github.com/open-feature/java-sdk/commit/015961b4fcce6ac2f24d17abedc01d1a48cc2672))
|
||||
* **deps:** update actions/setup-java digest to 2e74cbc ([#949](https://github.com/open-feature/java-sdk/issues/949)) ([0467e99](https://github.com/open-feature/java-sdk/commit/0467e999eea6bfe19c0c3bef8d92cf0e1b3a61d6))
|
||||
* **deps:** update actions/setup-java digest to fd08b9c ([#992](https://github.com/open-feature/java-sdk/issues/992)) ([0ec57a1](https://github.com/open-feature/java-sdk/commit/0ec57a1b0393437d910c81ca3e96d0bd171daa16))
|
||||
* **deps:** update amannn/action-semantic-pull-request digest to 80c0371 ([#994](https://github.com/open-feature/java-sdk/issues/994)) ([32b101e](https://github.com/open-feature/java-sdk/commit/32b101ed8f55b100554f2d5dc4e262563bd231dc))
|
||||
* **deps:** update amannn/action-semantic-pull-request digest to e32d7e6 ([#966](https://github.com/open-feature/java-sdk/issues/966)) ([dd33ec8](https://github.com/open-feature/java-sdk/commit/dd33ec82cbd2addc684c42258d44711fa10f0801))
|
||||
* **deps:** update codecov/codecov-action action to v4.4.0 ([#937](https://github.com/open-feature/java-sdk/issues/937)) ([0844c8f](https://github.com/open-feature/java-sdk/commit/0844c8f7420f2674b19c1496e524bd105b98604c))
|
||||
* **deps:** update codecov/codecov-action action to v4.4.1 ([#947](https://github.com/open-feature/java-sdk/issues/947)) ([be833a0](https://github.com/open-feature/java-sdk/commit/be833a07f28bc967c65153787e823cce0adcc92c))
|
||||
* **deps:** update codecov/codecov-action action to v4.5.0 ([#974](https://github.com/open-feature/java-sdk/issues/974)) ([59f9779](https://github.com/open-feature/java-sdk/commit/59f9779f19aab0f24d139c7e6a6a40f2c63103d2))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs to v4.8.5 ([#922](https://github.com/open-feature/java-sdk/issues/922)) ([5097d7c](https://github.com/open-feature/java-sdk/commit/5097d7ca0ffb9b3df22c89ec62b98235708bdb8c))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs to v4.8.6 ([#981](https://github.com/open-feature/java-sdk/issues/981)) ([8e17099](https://github.com/open-feature/java-sdk/commit/8e1709944f22921dba28748cd5ce02c2a027f564))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.5.0 ([#924](https://github.com/open-feature/java-sdk/issues/924)) ([3dfbfac](https://github.com/open-feature/java-sdk/commit/3dfbfac2684d5ae4633e8e3584aba728b0ce7827))
|
||||
* **deps:** update dependency com.github.spotbugs:spotbugs-maven-plugin to v4.8.6.1 ([#987](https://github.com/open-feature/java-sdk/issues/987)) ([616d7e7](https://github.com/open-feature/java-sdk/commit/616d7e7b0578624c92560fac0b2183e97ad30714))
|
||||
* **deps:** update dependency com.google.guava:guava to v33.2.1-jre ([#960](https://github.com/open-feature/java-sdk/issues/960)) ([65e2bf3](https://github.com/open-feature/java-sdk/commit/65e2bf3895eb9522390fb41621f8e132a0e51380))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-checkstyle-plugin to v3.4.0 ([#965](https://github.com/open-feature/java-sdk/issues/965)) ([6d6bcd1](https://github.com/open-feature/java-sdk/commit/6d6bcd1dea696fc8dac4b9b05426d8fced3ed9da))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-dependency-plugin to v3.7.0 ([#968](https://github.com/open-feature/java-sdk/issues/968)) ([82c265f](https://github.com/open-feature/java-sdk/commit/82c265f1685b099e8bca4918572267ca2d3ed4b7))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-dependency-plugin to v3.7.1 ([#984](https://github.com/open-feature/java-sdk/issues/984)) ([b128f13](https://github.com/open-feature/java-sdk/commit/b128f13e0be61946806fed70fbc43457fa92e62a))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.3.0 ([#977](https://github.com/open-feature/java-sdk/issues/977)) ([51721c2](https://github.com/open-feature/java-sdk/commit/51721c21638157ff116bd723f2e19d585d966c83))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-jar-plugin to v3.4.2 ([#983](https://github.com/open-feature/java-sdk/issues/983)) ([cc2989b](https://github.com/open-feature/java-sdk/commit/cc2989bb596aa592d04904f3ee93fbe546b16f0e))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-javadoc-plugin to v3.7.0 ([#961](https://github.com/open-feature/java-sdk/issues/961)) ([4420bca](https://github.com/open-feature/java-sdk/commit/4420bcaaa9c4f0f190796ba1ce61caf07a9515b0))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-pmd-plugin to v3.23.0 ([#969](https://github.com/open-feature/java-sdk/issues/969)) ([20ce4da](https://github.com/open-feature/java-sdk/commit/20ce4daa4a4f0d39bc791626bba2cb5d8c93309c))
|
||||
* **deps:** update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.3.0 ([#978](https://github.com/open-feature/java-sdk/issues/978)) ([078f94e](https://github.com/open-feature/java-sdk/commit/078f94edd9d6a497e771580935af3561c070c0ef))
|
||||
* **deps:** update dependency org.assertj:assertj-core to v3.26.0 ([#953](https://github.com/open-feature/java-sdk/issues/953)) ([340dd9c](https://github.com/open-feature/java-sdk/commit/340dd9c27ce2848e3875327aea4dd9c15fbbb803))
|
||||
* **deps:** update dependency org.codehaus.mojo:exec-maven-plugin to v3.3.0 ([#948](https://github.com/open-feature/java-sdk/issues/948)) ([c3c0fd2](https://github.com/open-feature/java-sdk/commit/c3c0fd2412504801fd8d976cf16344df98b13688))
|
||||
* **deps:** update dependency org.sonatype.plugins:nexus-staging-maven-plugin to v1.6.14 ([#954](https://github.com/open-feature/java-sdk/issues/954)) ([08e170e](https://github.com/open-feature/java-sdk/commit/08e170e24a293bb7474efcb4f32d3afda262e764))
|
||||
* **deps:** update dependency org.sonatype.plugins:nexus-staging-maven-plugin to v1.7.0 ([#956](https://github.com/open-feature/java-sdk/issues/956)) ([62bbd57](https://github.com/open-feature/java-sdk/commit/62bbd571e72d7618fc30fee4f9f4f0a8f2cb70af))
|
||||
* **deps:** update github/codeql-action digest to 08487db ([#932](https://github.com/open-feature/java-sdk/issues/932)) ([c94a0ba](https://github.com/open-feature/java-sdk/commit/c94a0ba8027c59aeced24af758fdb9eaf874d994))
|
||||
* **deps:** update github/codeql-action digest to 0d9161c ([#938](https://github.com/open-feature/java-sdk/issues/938)) ([00478ec](https://github.com/open-feature/java-sdk/commit/00478ec57b8188a3fefea66640fa7ecf861ce669))
|
||||
* **deps:** update github/codeql-action digest to 1428e58 ([#979](https://github.com/open-feature/java-sdk/issues/979)) ([a79c0ee](https://github.com/open-feature/java-sdk/commit/a79c0ee80a77321b4edb53a74978012d1da38b99))
|
||||
* **deps:** update github/codeql-action digest to 1e21373 ([#925](https://github.com/open-feature/java-sdk/issues/925)) ([81cba71](https://github.com/open-feature/java-sdk/commit/81cba711905dcd06f324cd6a445d455cd9e601ad))
|
||||
* **deps:** update github/codeql-action digest to 35619fb ([#980](https://github.com/open-feature/java-sdk/issues/980)) ([8928bd4](https://github.com/open-feature/java-sdk/commit/8928bd4ab811af63cba54956aad50e5c4449a8ae))
|
||||
* **deps:** update github/codeql-action digest to 3990b56 ([#975](https://github.com/open-feature/java-sdk/issues/975)) ([3fc7ccf](https://github.com/open-feature/java-sdk/commit/3fc7ccf88ac6435a0ba3bea80d1ebd353aaea876))
|
||||
* **deps:** update github/codeql-action digest to 3ce5d00 ([#985](https://github.com/open-feature/java-sdk/issues/985)) ([0dbdfa3](https://github.com/open-feature/java-sdk/commit/0dbdfa386dbe955419ba6c40e34d0f1c837e7eb7))
|
||||
* **deps:** update github/codeql-action digest to 4995c49 ([#930](https://github.com/open-feature/java-sdk/issues/930)) ([09c9a5c](https://github.com/open-feature/java-sdk/commit/09c9a5c254099f5e5b58746d2a1eed0b6191dc37))
|
||||
* **deps:** update github/codeql-action digest to 4a51972 ([#931](https://github.com/open-feature/java-sdk/issues/931)) ([29e6a90](https://github.com/open-feature/java-sdk/commit/29e6a90b102830c5112c079b4803c191dba1c232))
|
||||
* **deps:** update github/codeql-action digest to 4b812a5 ([#926](https://github.com/open-feature/java-sdk/issues/926)) ([23c01b9](https://github.com/open-feature/java-sdk/commit/23c01b9fa34b80d1667cbbfd07c1b0e496b1071c))
|
||||
* **deps:** update github/codeql-action digest to 5bf6dad ([#973](https://github.com/open-feature/java-sdk/issues/973)) ([d8db02f](https://github.com/open-feature/java-sdk/commit/d8db02f8727bb61eefe185e1f55e3f17409b14e0))
|
||||
* **deps:** update github/codeql-action digest to 63d519c ([#943](https://github.com/open-feature/java-sdk/issues/943)) ([1638b89](https://github.com/open-feature/java-sdk/commit/1638b8974f4131bd9e2d2328c27419d1406cc444))
|
||||
* **deps:** update github/codeql-action digest to 7927df0 ([#955](https://github.com/open-feature/java-sdk/issues/955)) ([a84f375](https://github.com/open-feature/java-sdk/commit/a84f37562e89b30401b8150b6929181055605392))
|
||||
* **deps:** update github/codeql-action digest to 7d9b7a1 ([#927](https://github.com/open-feature/java-sdk/issues/927)) ([0e3c10f](https://github.com/open-feature/java-sdk/commit/0e3c10fd741c3b808efec906e55f8aab52deb846))
|
||||
* **deps:** update github/codeql-action digest to 7fd4900 ([#935](https://github.com/open-feature/java-sdk/issues/935)) ([41213c7](https://github.com/open-feature/java-sdk/commit/41213c74227b1eedf5e35292eb829b6e6c7b9515))
|
||||
* **deps:** update github/codeql-action digest to 81b8143 ([#970](https://github.com/open-feature/java-sdk/issues/970)) ([f9ec8de](https://github.com/open-feature/java-sdk/commit/f9ec8de7b6d223976df5a7f4324ba56832fb06fe))
|
||||
* **deps:** update github/codeql-action digest to 8723b5b ([#986](https://github.com/open-feature/java-sdk/issues/986)) ([72b9ffe](https://github.com/open-feature/java-sdk/commit/72b9ffe5831efb0a2725efe91d16a55eab8974ed))
|
||||
* **deps:** update github/codeql-action digest to 8c4bc43 ([#952](https://github.com/open-feature/java-sdk/issues/952)) ([253f29d](https://github.com/open-feature/java-sdk/commit/253f29da2bf858cf31105c2bed5f12b9749e2ba5))
|
||||
* **deps:** update github/codeql-action digest to 8f1a6fe ([#963](https://github.com/open-feature/java-sdk/issues/963)) ([402cb1b](https://github.com/open-feature/java-sdk/commit/402cb1bc221b85c447726265f21dd097eddeacca))
|
||||
* **deps:** update github/codeql-action digest to 9550da9 ([#957](https://github.com/open-feature/java-sdk/issues/957)) ([71098a8](https://github.com/open-feature/java-sdk/commit/71098a85697eb6bf31d62142cf13da0a8cdb7132))
|
||||
* **deps:** update github/codeql-action digest to 9b7c22c ([#988](https://github.com/open-feature/java-sdk/issues/988)) ([f80a303](https://github.com/open-feature/java-sdk/commit/f80a303e3f2671157efcf409bfc45053a8aec03f))
|
||||
* **deps:** update github/codeql-action digest to 9c15e42 ([#962](https://github.com/open-feature/java-sdk/issues/962)) ([b3ba6fe](https://github.com/open-feature/java-sdk/commit/b3ba6fe5a2994f284724754d5e5c11648463cdf5))
|
||||
* **deps:** update github/codeql-action digest to a095bf2 ([#958](https://github.com/open-feature/java-sdk/issues/958)) ([27c9114](https://github.com/open-feature/java-sdk/commit/27c9114c589b26d028b5d8b5e2a8e0bc600b79bd))
|
||||
* **deps:** update github/codeql-action digest to acdf238 ([#950](https://github.com/open-feature/java-sdk/issues/950)) ([767e1ef](https://github.com/open-feature/java-sdk/commit/767e1ef04a6e1c54ed8d293190f91752ab391546))
|
||||
* **deps:** update github/codeql-action digest to add199b ([#959](https://github.com/open-feature/java-sdk/issues/959)) ([c363bdd](https://github.com/open-feature/java-sdk/commit/c363bdd1ca3dff452a589ec8cd74295ee44a0834))
|
||||
* **deps:** update github/codeql-action digest to b1bd8da ([#946](https://github.com/open-feature/java-sdk/issues/946)) ([bca1f0b](https://github.com/open-feature/java-sdk/commit/bca1f0bab67755236374c1b2afc5149f3a9833db))
|
||||
* **deps:** update github/codeql-action digest to bd2ebac ([#976](https://github.com/open-feature/java-sdk/issues/976)) ([a0b1d25](https://github.com/open-feature/java-sdk/commit/a0b1d25f4935f12fee321e4fa4751f6a7a7d8f53))
|
||||
* **deps:** update github/codeql-action digest to c36b5fc ([#971](https://github.com/open-feature/java-sdk/issues/971)) ([7cadadb](https://github.com/open-feature/java-sdk/commit/7cadadb8ec11013ab2df1a88df95ee58c662b16a))
|
||||
* **deps:** update github/codeql-action digest to c796494 ([#967](https://github.com/open-feature/java-sdk/issues/967)) ([4ea74d8](https://github.com/open-feature/java-sdk/commit/4ea74d8a0acc4fb215dbbb846533f17d4f276404))
|
||||
* **deps:** update github/codeql-action digest to ce5603b ([#982](https://github.com/open-feature/java-sdk/issues/982)) ([9ff353e](https://github.com/open-feature/java-sdk/commit/9ff353e509c8b17e65db01d731b3546bae3c5e07))
|
||||
* **deps:** update github/codeql-action digest to de94575 ([#991](https://github.com/open-feature/java-sdk/issues/991)) ([843b420](https://github.com/open-feature/java-sdk/commit/843b420cd197c0ce971a7466d1437be6871f2589))
|
||||
* **deps:** update github/codeql-action digest to def4d2c ([#929](https://github.com/open-feature/java-sdk/issues/929)) ([0c540f1](https://github.com/open-feature/java-sdk/commit/0c540f1f39f1b3e9576f0ff3f35dd774a257f1bd))
|
||||
* **deps:** update google-github-actions/release-please-action digest to e4dc86b ([#933](https://github.com/open-feature/java-sdk/issues/933)) ([2334906](https://github.com/open-feature/java-sdk/commit/2334906534d724c5a38df1ac6362759e7dbe1f96))
|
||||
* javadoc and tests for api, context ([#942](https://github.com/open-feature/java-sdk/issues/942)) ([4126b51](https://github.com/open-feature/java-sdk/commit/4126b511fbc442632dd60d0d308fdc220b2f2ae7))
|
||||
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
* remove golang snippet and fix variable name ([#964](https://github.com/open-feature/java-sdk/issues/964)) ([515f38b](https://github.com/open-feature/java-sdk/commit/515f38b3c7621ccf6b4dbe78a028e0b354367bc3))
|
||||
|
||||
## [1.8.0](https://github.com/open-feature/java-sdk/compare/v1.7.6...v1.8.0) (2024-05-03)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,21 +12,69 @@ Any contributions you make are expected to be tested with unit tests. You can va
|
|||
Further, it is recommended to verify code styling and static code analysis with `mvn verify -P !deploy`.
|
||||
Regardless, the automation itself will run them for you when you open a PR.
|
||||
|
||||
> [!TIP]
|
||||
> For easier usage maven wrapper is available. Example usage: `./mvnw verify`
|
||||
|
||||
Your code is supposed to work with Java 8+.
|
||||
|
||||
If you think we might be out of date with the spec, you can check that by invoking `python spec_finder.py` in the root of the repository. This will validate we have tests defined for all of the specification entries we know about.
|
||||
|
||||
If you're adding tests to cover something in the spec, use the `@Specification` annotation like you see throughout the test suites.
|
||||
|
||||
## Code Styles
|
||||
|
||||
### Overview
|
||||
Our project follows strict code formatting standards to maintain consistency and readability across the codebase. We use [Spotless](https://github.com/diffplug/spotless) integrated with the [Palantir Java Format](https://github.com/palantir/palantir-java-format) for code formatting.
|
||||
|
||||
**Spotless** ensures that all code complies with the formatting rules automatically, reducing style-related issues during code reviews.
|
||||
|
||||
### How to Format Your Code
|
||||
1. **Before Committing Changes:**
|
||||
Run the Spotless plugin to format your code. This will apply the Palantir Java Format style:
|
||||
```bash
|
||||
mvn spotless:apply
|
||||
```
|
||||
|
||||
2. **Verify Formatting:**
|
||||
To check if your code adheres to the style guidelines without making changes:
|
||||
```bash
|
||||
mvn spotless:check
|
||||
```
|
||||
|
||||
- If this command fails, your code does not follow the required formatting. Use `mvn spotless:apply` to fix it.
|
||||
|
||||
### CI/CD Integration
|
||||
Our Continuous Integration (CI) pipeline automatically checks code formatting using the Spotless plugin. Any code that does not pass the `spotless:check` step will cause the build to fail.
|
||||
|
||||
### Best Practices
|
||||
- Regularly run `mvn spotless:apply` during your work to ensure your code remains aligned with the standards.
|
||||
- Configure your IDE (e.g., IntelliJ IDEA or Eclipse) to follow the Palantir Java format guidelines to reduce discrepancies during development.
|
||||
|
||||
### Support
|
||||
If you encounter issues with code formatting, please raise a GitHub issue or contact the maintainers.
|
||||
|
||||
## End-to-End Tests
|
||||
|
||||
The continuous integration runs a set of [gherkin e2e tests](https://github.com/open-feature/test-harness/blob/main/features/evaluation.feature) using `InMemoryProvider`.
|
||||
The continuous integration runs a set of [gherkin e2e tests](https://github.com/open-feature/spec/blob/main/specification/assets/gherkin/evaluation.feature) using `InMemoryProvider`.
|
||||
|
||||
to run alone:
|
||||
```
|
||||
mvn test -P e2e
|
||||
```
|
||||
|
||||
## Benchmarking
|
||||
|
||||
There is a small JMH benchmark suite for testing allocations that can be run with:
|
||||
|
||||
```sh
|
||||
mvn -P benchmark clean compile test-compile jmh:benchmark -Djmh.f=1 -Djmh.prof='dev.openfeature.sdk.benchmark.AllocationProfiler'
|
||||
```
|
||||
|
||||
If you are concerned about the repercussions of a change on memory usage, run this an compare the results to the committed. `benchmark.txt` file.
|
||||
Note that the ONLY MEANINGFUL RESULTS of this benchmark are the `totalAllocatedBytes` and the `totalAllocatedInstances`.
|
||||
The `run` score, and maven task time are not relevant since this benchmark is purely memory-related and has nothing to do with speed.
|
||||
You can also view the heap breakdown to see which objects are taking up the most memory.
|
||||
|
||||
## Releasing
|
||||
|
||||
See [releasing](./docs/release.md).
|
||||
|
|
120
README.md
120
README.md
|
@ -18,8 +18,8 @@
|
|||
</a>
|
||||
<!-- x-release-please-start-version -->
|
||||
|
||||
<a href="https://github.com/open-feature/java-sdk/releases/tag/v1.8.0">
|
||||
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.8.0&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,9 +46,9 @@
|
|||
|
||||
### 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 in mobile devices.
|
||||
Note that this library is intended to be used in server-side contexts and has not been evaluated for use on mobile devices.
|
||||
|
||||
### Install
|
||||
|
||||
|
@ -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.8.0</version>
|
||||
<version>1.16.0</version>
|
||||
</dependency>
|
||||
```
|
||||
<!-- x-release-please-end-version -->
|
||||
|
@ -72,8 +72,8 @@ If you would like snapshot builds, this is the relevant repository information:
|
|||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<id>sonartype</id>
|
||||
<name>Sonartype Repository</name>
|
||||
<id>sonatype</id>
|
||||
<name>Sonatype Repository</name>
|
||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
@ -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.8.0'
|
||||
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();
|
||||
|
@ -120,17 +125,18 @@ See [here](https://javadoc.io/doc/dev.openfeature/sdk/latest/) for the Javadocs.
|
|||
|
||||
## 🌟 Features
|
||||
|
||||
| Status | Features | Description |
|
||||
| ------ |-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
|
||||
| ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
|
||||
| ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
|
||||
| ✅ | [Logging](#logging) | Integrate with popular logging packages. |
|
||||
| ✅ | [Named clients](#named-clients) | Utilize multiple providers in a single application. |
|
||||
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
|
||||
| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
|
||||
| ✅ | [Transaction Context Propagation](#transaction-context-propagation) | Set a specific [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) for a transaction (e.g. an HTTP request or a thread). |
|
||||
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
|
||||
| Status | Features | Description |
|
||||
| ------ |---------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
|
||||
| ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
|
||||
| ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
|
||||
| ✅ | [Tracking](#tracking) | Associate user actions with feature flag evaluations. |
|
||||
| ✅ | [Logging](#logging) | Integrate with popular logging packages. |
|
||||
| ✅ | [Domains](#domains) | Logically bind clients with providers. |
|
||||
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
|
||||
| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
|
||||
| ✅ | [Transaction Context Propagation](#transaction-context-propagation) | Set a specific [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context) for a transaction (e.g. an HTTP request or a thread). |
|
||||
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
|
||||
|
||||
<sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>
|
||||
|
||||
|
@ -148,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
|
||||
|
@ -160,7 +171,7 @@ To register a provider in a non-blocking manner, you can use the `setProvider` m
|
|||
```
|
||||
|
||||
In some situations, it may be beneficial to register multiple providers in the same application.
|
||||
This is possible using [named clients](#named-clients), which is covered in more details below.
|
||||
This is possible using [domains](#domains), which is covered in more detail below.
|
||||
|
||||
### Targeting
|
||||
|
||||
|
@ -215,31 +226,49 @@ Once you've added a hook as a dependency, it can be registered at the global, cl
|
|||
FlagEvaluationOptions.builder().hook(new ExampleHook()).build());
|
||||
```
|
||||
|
||||
### Tracking
|
||||
|
||||
The [tracking API](https://openfeature.dev/specification/sections/tracking/) allows you to use OpenFeature abstractions to associate user actions with feature flag evaluations.
|
||||
This is essential for robust experimentation powered by feature flags. Note that, unlike methods that handle feature flag evaluations, calling `track(...)` may throw an `IllegalArgumentException` if an empty string is passed as the `trackingEventName`.
|
||||
|
||||
```java
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
api.getClient().track("visited-promo-page", new MutableTrackingEventDetails(99.77).add("currency", "USD"));
|
||||
```
|
||||
|
||||
### Logging
|
||||
|
||||
The Java SDK uses SLF4J. See the [SLF4J manual](https://slf4j.org/manual.html) for complete documentation.
|
||||
Note that in accordance with the OpenFeature specification, the SDK doesn't generally log messages during flag evaluation.
|
||||
|
||||
### Named clients
|
||||
#### Logging Hook
|
||||
|
||||
Clients can be given a name.
|
||||
A name is a logical identifier which can be used to associate clients with a particular provider.
|
||||
If a name has no associated provider, the global provider is used.
|
||||
The Java SDK includes a `LoggingHook`, which logs detailed information at key points during flag evaluation, using SLF4J's structured logging API.
|
||||
This hook can be particularly helpful for troubleshooting and debugging; simply attach it at the global, client or invocation level and ensure your log level is set to "debug".
|
||||
|
||||
See [hooks](#hooks) for more information on configuring hooks.
|
||||
|
||||
### Domains
|
||||
|
||||
Clients can be assigned to a domain.
|
||||
A domain is a logical identifier which can be used to associate clients with a particular provider.
|
||||
If a domain has no associated provider, the global provider is used.
|
||||
|
||||
```java
|
||||
FeatureProvider scopedProvider = new MyProvider();
|
||||
|
||||
// registering the default provider
|
||||
OpenFeatureAPI.getInstance().setProvider(LocalProvider());
|
||||
// registering a named provider
|
||||
OpenFeatureAPI.getInstance().setProvider("clientForCache", new CachedProvider());
|
||||
// registering a provider to a domain
|
||||
OpenFeatureAPI.getInstance().setProvider("my-domain", new CachedProvider());
|
||||
|
||||
// a client backed by default provider
|
||||
// A client bound to the default provider
|
||||
Client clientDefault = OpenFeatureAPI.getInstance().getClient();
|
||||
// a client backed by CachedProvider
|
||||
Client clientNamed = OpenFeatureAPI.getInstance().getClient("clientForCache");
|
||||
// A client bound to the CachedProvider provider
|
||||
Client domainScopedClient = OpenFeatureAPI.getInstance().getClient("my-domain");
|
||||
```
|
||||
|
||||
Named providers can be set in a blocking or non-blocking way.
|
||||
Providers for domains can be set in a blocking or non-blocking way.
|
||||
For more details, please refer to the [providers](#providers) section.
|
||||
|
||||
### Eventing
|
||||
|
@ -282,7 +311,7 @@ To register a `ThreadLocal` context propagator, you can use the `setTransactionC
|
|||
// registering the ThreadLocalTransactionContextPropagator
|
||||
OpenFeatureAPI.getInstance().setTransactionContextPropagator(new ThreadLocalTransactionContextPropagator());
|
||||
```
|
||||
Once you've registered a transaction context propagator, you can propagate the data into request scoped transaction context.
|
||||
Once you've registered a transaction context propagator, you can propagate the data into request-scoped transaction context.
|
||||
|
||||
```java
|
||||
// adding userId to transaction context
|
||||
|
@ -290,7 +319,7 @@ OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
|||
Map<String, Value> transactionAttrs = new HashMap<>();
|
||||
transactionAttrs.put("userId", new Value("userId"));
|
||||
EvaluationContext transactionCtx = new ImmutableContext(transactionAttrs);
|
||||
api.setTransactionContext(apiCtx);
|
||||
api.setTransactionContext(transactionCtx);
|
||||
```
|
||||
Additionally, you can develop a custom transaction context propagator by implementing the `TransactionContextPropagator` interface and registering it as shown above.
|
||||
|
||||
|
@ -309,11 +338,6 @@ public class MyProvider implements FeatureProvider {
|
|||
return () -> "My Provider";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderState getState() {
|
||||
// optionally indicate your provider's state (assumed to be READY if not implemented)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(EvaluationContext evaluationContext) throws Exception {
|
||||
// start up your provider
|
||||
|
@ -360,11 +384,6 @@ class MyEventProvider extends EventProvider {
|
|||
return () -> "My Event Provider";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderState getState() {
|
||||
// indicate your provider's state (required for EventProviders)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(EvaluationContext evaluationContext) throws Exception {
|
||||
// emit events when flags are changed in a hypothetical REST API
|
||||
|
@ -383,6 +402,13 @@ class MyEventProvider extends EventProvider {
|
|||
}
|
||||
```
|
||||
|
||||
Providers no longer need to manage their own state, this is done by the SDK itself. If desired, the state of a provider
|
||||
can be queried through the client that uses the provider.
|
||||
|
||||
```java
|
||||
OpenFeatureAPI.getInstance().getClient().getProviderState();
|
||||
```
|
||||
|
||||
> Built a new provider? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=provider&projects=&template=document-provider.yaml&title=%5BProvider%5D%3A+) so we can add it to the docs!
|
||||
|
||||
### Develop a hook
|
||||
|
@ -390,8 +416,6 @@ class MyEventProvider extends EventProvider {
|
|||
To develop a hook, you need to create a new project and include the OpenFeature SDK as a dependency.
|
||||
This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/java-sdk-contrib) available under the OpenFeature organization.
|
||||
Implement your own hook by conforming to the `Hook interface`.
|
||||
To satisfy the interface, all methods (`Before`/`After`/`Finally`/`Error`) need to be defined.
|
||||
To avoid defining empty functions make use of the `UnimplementedHook` struct (which already implements all the empty functions).
|
||||
|
||||
```java
|
||||
class MyHook implements Hook {
|
||||
|
@ -412,7 +436,7 @@ class MyHook implements Hook {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void finallyAfter(HookContext ctx, Map hints) {
|
||||
public void finallyAfter(HookContext ctx, FlagEvaluationDetails details, Map hints) {
|
||||
// code that runs regardless of success or error
|
||||
}
|
||||
};
|
||||
|
@ -434,7 +458,7 @@ class MyHook implements Hook {
|
|||
|
||||
Interested in contributing? Great, we'd love your help! To get started, take a look at the [CONTRIBUTING](CONTRIBUTING.md) guide.
|
||||
|
||||
### Thanks to everyone that has already contributed
|
||||
### Thanks to everyone who has already contributed
|
||||
|
||||
<a href="https://github.com/open-feature/java-sdk/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=open-feature/java-sdk" alt="Pictures of the folks who have contributed to the project" />
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] ------------------------< dev.openfeature:sdk >-------------------------
|
||||
[INFO] Building OpenFeature Java SDK 1.12.1
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[WARNING] Parameter 'encoding' is unknown for plugin 'maven-checkstyle-plugin:3.5.0:check (validate)'
|
||||
[WARNING] Parameter 'encoding' is unknown for plugin 'maven-checkstyle-plugin:3.5.0:check (validate)'
|
||||
[WARNING] Parameter 'encoding' is unknown for plugin 'maven-checkstyle-plugin:3.5.0:check (validate)'
|
||||
[INFO]
|
||||
[INFO] --- clean:3.2.0:clean (default-clean) @ sdk ---
|
||||
[INFO] Deleting /home/todd/git/java-sdk/target
|
||||
[INFO]
|
||||
[INFO] --- checkstyle:3.5.0:check (validate) @ sdk ---
|
||||
[INFO] Starting audit...
|
||||
Audit done.
|
||||
[INFO] You have 0 Checkstyle violations.
|
||||
[INFO]
|
||||
[INFO] --- jacoco:0.8.12:prepare-agent (prepare-agent) @ sdk ---
|
||||
[INFO] surefireArgLine set to -javaagent:/home/todd/.m2/repository/org/jacoco/org.jacoco.agent/0.8.12/org.jacoco.agent-0.8.12-runtime.jar=destfile=/home/todd/git/java-sdk/target/coverage-reports/jacoco-ut.exec
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ sdk ---
|
||||
[INFO] skip non existing resourceDirectory /home/todd/git/java-sdk/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ sdk ---
|
||||
[INFO] Recompiling the module because of changed source code.
|
||||
[INFO] Compiling 65 source files with javac [debug target 1.8] to target/classes
|
||||
[WARNING] bootstrap class path not set in conjunction with -source 8
|
||||
[WARNING] source value 8 is obsolete and will be removed in a future release
|
||||
[WARNING] target value 8 is obsolete and will be removed in a future release
|
||||
[WARNING] To suppress warnings about obsolete options, use -Xlint:-options.
|
||||
[INFO] Annotation processing is enabled because one or more processors were found
|
||||
on the class path. A future release of javac may disable annotation processing
|
||||
unless at least one processor is specified by name (-processor), or a search
|
||||
path is specified (--processor-path, --processor-module-path), or annotation
|
||||
processing is enabled explicitly (-proc:only, -proc:full).
|
||||
Use -Xlint:-options to suppress this message.
|
||||
Use -proc:none to disable annotation processing.
|
||||
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/MutableStructure.java:[19,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
|
||||
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/ImmutableStructure.java:[22,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
|
||||
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/EventDetails.java:[9,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
|
||||
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/Value.java:[27,26] finalize() in java.lang.Object has been deprecated and marked for removal
|
||||
[INFO] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/NoOpProvider.java: Some input files use or override a deprecated API.
|
||||
[INFO] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/NoOpProvider.java: Recompile with -Xlint:deprecation for details.
|
||||
[INFO] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/Value.java: Some input files use unchecked or unsafe operations.
|
||||
[INFO] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/Value.java: Recompile with -Xlint:unchecked for details.
|
||||
[INFO]
|
||||
[INFO] --- checkstyle:3.5.0:check (validate) @ sdk ---
|
||||
[INFO] Starting audit...
|
||||
Audit done.
|
||||
[INFO] You have 0 Checkstyle violations.
|
||||
[INFO]
|
||||
[INFO] --- jacoco:0.8.12:prepare-agent (prepare-agent) @ sdk ---
|
||||
[INFO] surefireArgLine set to -javaagent:/home/todd/.m2/repository/org/jacoco/org.jacoco.agent/0.8.12/org.jacoco.agent-0.8.12-runtime.jar=destfile=/home/todd/git/java-sdk/target/coverage-reports/jacoco-ut.exec
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ sdk ---
|
||||
[INFO] skip non existing resourceDirectory /home/todd/git/java-sdk/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ sdk ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ sdk ---
|
||||
[INFO] Copying 2 resources from src/test/resources to target/test-classes
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ sdk ---
|
||||
[INFO] Recompiling the module because of changed dependency.
|
||||
[INFO] Compiling 52 source files with javac [debug target 1.8] to target/test-classes
|
||||
[WARNING] bootstrap class path not set in conjunction with -source 8
|
||||
[WARNING] source value 8 is obsolete and will be removed in a future release
|
||||
[WARNING] target value 8 is obsolete and will be removed in a future release
|
||||
[WARNING] To suppress warnings about obsolete options, use -Xlint:-options.
|
||||
[INFO] Annotation processing is enabled because one or more processors were found
|
||||
on the class path. A future release of javac may disable annotation processing
|
||||
unless at least one processor is specified by name (-processor), or a search
|
||||
path is specified (--processor-path, --processor-module-path), or annotation
|
||||
processing is enabled explicitly (-proc:only, -proc:full).
|
||||
Use -Xlint:-options to suppress this message.
|
||||
Use -proc:none to disable annotation processing.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/EventsTest.java: Some input files use or override a deprecated API.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/EventsTest.java: Recompile with -Xlint:deprecation for details.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/HookSpecTest.java: Some input files use unchecked or unsafe operations.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/HookSpecTest.java: Recompile with -Xlint:unchecked for details.
|
||||
[INFO]
|
||||
[INFO] >>> jmh:0.2.2:benchmark (default-cli) > process-test-resources @ sdk >>>
|
||||
[INFO]
|
||||
[INFO] --- checkstyle:3.5.0:check (validate) @ sdk ---
|
||||
[INFO] Starting audit...
|
||||
Audit done.
|
||||
[INFO] You have 0 Checkstyle violations.
|
||||
[INFO]
|
||||
[INFO] --- jacoco:0.8.12:prepare-agent (prepare-agent) @ sdk ---
|
||||
[INFO] surefireArgLine set to -javaagent:/home/todd/.m2/repository/org/jacoco/org.jacoco.agent/0.8.12/org.jacoco.agent-0.8.12-runtime.jar=destfile=/home/todd/git/java-sdk/target/coverage-reports/jacoco-ut.exec
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:resources (default-resources) @ sdk ---
|
||||
[INFO] skip non existing resourceDirectory /home/todd/git/java-sdk/src/main/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.13.0:compile (default-compile) @ sdk ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.3.1:testResources (default-testResources) @ sdk ---
|
||||
[INFO] Copying 2 resources from src/test/resources to target/test-classes
|
||||
[INFO]
|
||||
[INFO] <<< jmh:0.2.2:benchmark (default-cli) < process-test-resources @ sdk <<<
|
||||
[INFO]
|
||||
[INFO]
|
||||
[INFO] --- jmh:0.2.2:benchmark (default-cli) @ sdk ---
|
||||
[INFO] Changes detected - recompiling the module!
|
||||
[INFO] Compiling 52 source files to /home/todd/git/java-sdk/target/test-classes
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/LockingTest.java: Some input files use or override a deprecated API.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/LockingTest.java: Recompile with -Xlint:deprecation for details.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/internal/TriConsumerTest.java: Some input files use unchecked or unsafe operations.
|
||||
[INFO] /home/todd/git/java-sdk/src/test/java/dev/openfeature/sdk/internal/TriConsumerTest.java: Recompile with -Xlint:unchecked for details.
|
||||
[INFO] Executing the JMH benchmarks
|
||||
# JMH version: 1.37
|
||||
# VM version: JDK 21.0.4, OpenJDK 64-Bit Server VM, 21.0.4+7
|
||||
# VM invoker: /usr/lib/jvm/java-21-openjdk/bin/java
|
||||
# VM options: -Xmx1024m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC
|
||||
# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
|
||||
# Warmup: <none>
|
||||
# Measurement: 1 iterations, single-shot each
|
||||
# Timeout: 10 min per iteration
|
||||
# Threads: 1 thread
|
||||
# Benchmark mode: Single shot invocation time
|
||||
# Benchmark: dev.openfeature.sdk.benchmark.AllocationBenchmark.run
|
||||
|
||||
# Run progress: 0.00% complete, ETA 00:00:00
|
||||
# Fork: 1 of 1
|
||||
[0.001s][warning][gc,init] Consider setting -Xms equal to -Xmx to avoid resizing hiccups
|
||||
[0.001s][warning][gc,init] Consider enabling -XX:+AlwaysPreTouch to avoid memory commit hiccups
|
||||
Iteration 1: num #instances #bytes class name (module)
|
||||
-------------------------------------------------------
|
||||
1: 480234 23051232 java.util.HashMap (java.base@21.0.4)
|
||||
2: 150497 12050088 [Ljava.util.HashMap$Node; (java.base@21.0.4)
|
||||
3: 332017 10624544 java.util.HashMap$Node (java.base@21.0.4)
|
||||
4: 47815 9732480 [B (java.base@21.0.4)
|
||||
5: 305991 8105872 [Ljava.lang.Object; (java.base@21.0.4)
|
||||
6: 366682 5866912 java.util.Optional (java.base@21.0.4)
|
||||
7: 183332 5866624 java.util.HashMap$EntryIterator (java.base@21.0.4)
|
||||
8: 172970 5535040 java.util.Collections$UnmodifiableMap (java.base@21.0.4)
|
||||
9: 100000 4000000 dev.openfeature.sdk.HookContext
|
||||
10: 100000 4000000 dev.openfeature.sdk.HookContext$HookContextBuilder
|
||||
11: 230006 3680096 dev.openfeature.sdk.Value
|
||||
12: 200062 3200992 java.util.HashMap$EntrySet (java.base@21.0.4)
|
||||
13: 132870 3188880 java.util.ArrayList (java.base@21.0.4)
|
||||
14: 192292 3076672 dev.openfeature.sdk.ImmutableStructure
|
||||
15: 182292 2916672 dev.openfeature.sdk.ImmutableContext
|
||||
16: 50000 2000000 dev.openfeature.sdk.FlagEvaluationDetails
|
||||
17: 50000 2000000 dev.openfeature.sdk.ProviderEvaluation
|
||||
18: 122968 1967488 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet (java.base@21.0.4)
|
||||
19: 149 1884376 [Ljdk.internal.vm.FillerElement; (java.base@21.0.4)
|
||||
20: 56476 1807232 java.util.ArrayList$Itr (java.base@21.0.4)
|
||||
21: 37481 1799088 dev.openfeature.sdk.FlagEvaluationDetails$FlagEvaluationDetailsBuilder
|
||||
22: 100001 1600016 dev.openfeature.sdk.NoOpProvider$$Lambda/0x000076e79c02fa78
|
||||
23: 50000 1600000 [Ldev.openfeature.sdk.EvaluationContext;
|
||||
24: 50000 1600000 [Ljava.util.List; (java.base@21.0.4)
|
||||
25: 100000 1600000 dev.openfeature.sdk.OpenFeatureClient$$Lambda/0x000076e79c082800
|
||||
26: 36720 1468800 dev.openfeature.sdk.ProviderEvaluation$ProviderEvaluationBuilder
|
||||
27: 87481 1399696 dev.openfeature.sdk.ImmutableMetadata
|
||||
28: 50000 1200000 dev.openfeature.sdk.FlagEvaluationOptions
|
||||
29: 74201 1187216 dev.openfeature.sdk.ImmutableMetadata$ImmutableMetadataBuilder
|
||||
30: 73235 1171760 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry (java.base@21.0.4)
|
||||
31: 45869 1100856 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1 (java.base@21.0.4)
|
||||
32: 43776 1050624 dev.openfeature.sdk.FlagEvaluationOptions$FlagEvaluationOptionsBuilder
|
||||
33: 40016 960384 dev.openfeature.sdk.HookSupport$$Lambda/0x000076e79c081b78
|
||||
34: 39967 959208 dev.openfeature.sdk.HookSupport$$Lambda/0x000076e79c081da8
|
||||
35: 57783 924528 dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock$$Lambda/0x000076e79c02eae8
|
||||
36: 4490 721440 [I (java.base@21.0.4)
|
||||
37: 26594 638256 java.lang.String (java.base@21.0.4)
|
||||
38: 1461 390008 [J (java.base@21.0.4)
|
||||
39: 2361 288784 java.lang.Class (java.base@21.0.4)
|
||||
40: 4632 259392 jdk.internal.org.objectweb.asm.SymbolTable$Entry (java.base@21.0.4)
|
||||
41: 10001 240024 java.lang.Double (java.base@21.0.4)
|
||||
42: 2502 180144 java.lang.reflect.Field (java.base@21.0.4)
|
||||
43: 6007 144168 java.lang.StringBuilder (java.base@21.0.4)
|
||||
44: 180 140968 [Ljdk.internal.org.objectweb.asm.SymbolTable$Entry; (java.base@21.0.4)
|
||||
45: 3827 122464 java.util.concurrent.ConcurrentHashMap$Node (java.base@21.0.4)
|
||||
46: 48 122168 [C (java.base@21.0.4)
|
||||
47: 1440 113512 [S (java.base@21.0.4)
|
||||
48: 1201 105688 java.lang.reflect.Method (java.base@21.0.4)
|
||||
49: 3031 79600 [Ljava.lang.Class; (java.base@21.0.4)
|
||||
50: 1351 75656 jdk.internal.org.objectweb.asm.Label (java.base@21.0.4)
|
||||
51: 1561 74928 java.lang.invoke.MemberName (java.base@21.0.4)
|
||||
52: 334 74816 jdk.internal.org.objectweb.asm.MethodWriter (java.base@21.0.4)
|
||||
53: 1799 71960 java.lang.invoke.MethodType (java.base@21.0.4)
|
||||
54: 1089 69696 java.net.URL (java.base@21.0.4)
|
||||
55: 121 50512 [Ljava.util.concurrent.ConcurrentHashMap$Node; (java.base@21.0.4)
|
||||
56: 3147 50352 jdk.internal.util.StrongReferenceKey (java.base@21.0.4)
|
||||
57: 1057 42280 java.io.ObjectStreamField (java.base@21.0.4)
|
||||
58: 1225 39200 java.io.File (java.base@21.0.4)
|
||||
59: 779 37392 jdk.internal.org.objectweb.asm.Frame (java.base@21.0.4)
|
||||
60: 243 25272 java.util.jar.JarFile$JarFileEntry (java.base@21.0.4)
|
||||
61: 794 25248 [Ljava.lang.String; (java.base@21.0.4)
|
||||
62: 622 24880 java.lang.NoSuchFieldException (java.base@21.0.4)
|
||||
63: 571 22840 java.util.LinkedHashMap$Entry (java.base@21.0.4)
|
||||
64: 474 22752 jdk.internal.ref.CleanerImpl$PhantomCleanableRef (java.base@21.0.4)
|
||||
65: 690 22080 jdk.internal.util.WeakReferenceKey (java.base@21.0.4)
|
||||
66: 828 19872 jdk.internal.org.objectweb.asm.ByteVector (java.base@21.0.4)
|
||||
67: 248 18848 [Ljava.lang.ref.SoftReference; (java.base@21.0.4)
|
||||
68: 118 17936 jdk.internal.org.objectweb.asm.ClassWriter (java.base@21.0.4)
|
||||
69: 380 16824 [Ljava.lang.invoke.LambdaForm$Name; (java.base@21.0.4)
|
||||
70: 625 15000 java.lang.Long (java.base@21.0.4)
|
||||
71: 463 14816 java.lang.invoke.LambdaForm$Name (java.base@21.0.4)
|
||||
72: 904 14464 java.lang.Object (java.base@21.0.4)
|
||||
73: 198 14256 java.lang.reflect.Constructor (java.base@21.0.4)
|
||||
74: 249 13944 java.util.zip.ZipFile$ZipFileInputStream (java.base@21.0.4)
|
||||
75: 334 13360 jdk.internal.org.objectweb.asm.Handler (java.base@21.0.4)
|
||||
76: 202 12928 java.util.concurrent.ConcurrentHashMap (java.base@21.0.4)
|
||||
77: 201 12864 jdk.internal.org.objectweb.asm.FieldWriter (java.base@21.0.4)
|
||||
78: 316 12640 java.util.WeakHashMap$Entry (java.base@21.0.4)
|
||||
79: 102 12240 java.io.ObjectStreamClass (java.base@21.0.4)
|
||||
80: 249 11952 java.util.zip.ZipFile$ZipFileInflaterInputStream (java.base@21.0.4)
|
||||
81: 359 11488 jdk.internal.org.objectweb.asm.Type (java.base@21.0.4)
|
||||
82: 465 11160 java.lang.invoke.ResolvedMethodName (java.base@21.0.4)
|
||||
83: 464 11136 jdk.internal.org.objectweb.asm.Edge (java.base@21.0.4)
|
||||
84: 341 10912 jdk.internal.math.FDBigInteger (java.base@21.0.4)
|
||||
85: 94 10728 [Ljava.lang.reflect.Field; (java.base@21.0.4)
|
||||
86: 266 10640 java.lang.NoSuchMethodException (java.base@21.0.4)
|
||||
87: 266 10640 java.security.CodeSource (java.base@21.0.4)
|
||||
88: 221 10608 java.lang.invoke.DirectMethodHandle$Constructor (java.base@21.0.4)
|
||||
89: 264 10560 sun.security.util.KnownOIDs (java.base@21.0.4)
|
||||
90: 75 10200 sun.nio.fs.UnixFileAttributes (java.base@21.0.4)
|
||||
91: 245 9800 java.lang.ref.SoftReference (java.base@21.0.4)
|
||||
92: 118 9440 jdk.internal.event.DeserializationEvent (java.base@21.0.4)
|
||||
93: 115 9200 [Ljava.util.WeakHashMap$Entry; (java.base@21.0.4)
|
||||
94: 368 8832 java.lang.module.ModuleDescriptor$Exports (java.base@21.0.4)
|
||||
95: 63 8384 [Ljava.lang.invoke.MethodHandle; (java.base@21.0.4)
|
||||
96: 146 8176 java.io.FileCleanable (java.base@21.0.4)
|
||||
97: 125 8000 java.lang.Class$ReflectionData (java.base@21.0.4)
|
||||
98: 323 7752 java.util.ImmutableCollections$Set12 (java.base@21.0.4)
|
||||
99: 121 7744 jdk.internal.org.objectweb.asm.SymbolTable (java.base@21.0.4)
|
||||
100: 70 7280 java.lang.invoke.InnerClassLambdaMetafactory (java.base@21.0.4)
|
||||
101: 144 6912 jdk.internal.org.objectweb.asm.AnnotationWriter (java.base@21.0.4)
|
||||
102: 167 6680 jdk.internal.loader.URLClassPath$JarLoader$2 (java.base@21.0.4)
|
||||
103: 199 6368 java.lang.invoke.MethodHandles$Lookup (java.base@21.0.4)
|
||||
104: 156 6240 java.util.StringJoiner (java.base@21.0.4)
|
||||
105: 153 6120 java.io.FileDescriptor (java.base@21.0.4)
|
||||
106: 126 6048 java.lang.invoke.LambdaForm (java.base@21.0.4)
|
||||
107: 77 6016 [Ljava.lang.reflect.Method; (java.base@21.0.4)
|
||||
108: 249 5976 java.util.zip.ZipFile$InflaterCleanupAction (java.base@21.0.4)
|
||||
109: 373 5968 java.lang.Byte (java.base@21.0.4)
|
||||
110: 74 5920 java.util.zip.ZipFile$Source (java.base@21.0.4)
|
||||
111: 82 5720 [Ljava.io.ObjectStreamField; (java.base@21.0.4)
|
||||
112: 40 5640 [Ljava.lang.ClassValue$Entry; (java.base@21.0.4)
|
||||
113: 234 5616 java.util.jar.Attributes$Name (java.base@21.0.4)
|
||||
114: 174 5568 java.util.concurrent.locks.ReentrantLock$NonfairSync (java.base@21.0.4)
|
||||
115: 98 5488 java.lang.Module (java.base@21.0.4)
|
||||
116: 219 5256 java.lang.PublicMethods$MethodList (java.base@21.0.4)
|
||||
117: 65 5200 java.net.URI (java.base@21.0.4)
|
||||
118: 215 5104 [Ljdk.internal.org.objectweb.asm.Type; (java.base@21.0.4)
|
||||
truncated...
|
||||
Total 4452140 139359040
|
||||
|
||||
0.186 s/op
|
||||
+totalAllocatedBytes: 139359040.000 bytes
|
||||
+totalAllocatedInstances: 4452140.000 instances
|
||||
+totalHeap: 521412608.000 bytes
|
||||
|
||||
|
||||
|
||||
Secondary result "dev.openfeature.sdk.benchmark.AllocationBenchmark.run:+totalAllocatedBytes":
|
||||
139359040.000 bytes
|
||||
|
||||
Secondary result "dev.openfeature.sdk.benchmark.AllocationBenchmark.run:+totalAllocatedInstances":
|
||||
4452140.000 instances
|
||||
|
||||
Secondary result "dev.openfeature.sdk.benchmark.AllocationBenchmark.run:+totalHeap":
|
||||
521412608.000 bytes
|
||||
|
||||
|
||||
# Run complete. Total time: 00:00:00
|
||||
|
||||
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
|
||||
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
|
||||
experiments, perform baseline and negative tests that provide experimental control, make sure
|
||||
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
|
||||
Do not assume the numbers tell you what you want them to tell.
|
||||
|
||||
NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in use. Please exercise
|
||||
extra caution when trusting the results, look into the generated code to check the benchmark still
|
||||
works, and factor in a small probability of new VM bugs. Additionally, while comparisons between
|
||||
different JVMs are already problematic, the performance difference caused by different Blackhole
|
||||
modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons.
|
||||
|
||||
Benchmark Mode Cnt Score Error Units
|
||||
AllocationBenchmark.run ss 0.186 s/op
|
||||
AllocationBenchmark.run:+totalAllocatedBytes ss 139359040.000 bytes
|
||||
AllocationBenchmark.run:+totalAllocatedInstances ss 4452140.000 instances
|
||||
AllocationBenchmark.run:+totalHeap ss 521412608.000 bytes
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 8.280 s
|
||||
[INFO] Finished at: 2024-10-23T12:37:24-04:00
|
||||
[INFO] ------------------------------------------------------------------------
|
261
checkstyle.xml
261
checkstyle.xml
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
|
||||
<!--
|
||||
Checkstyle configuration that checks the Google coding conventions from Google Java Style
|
||||
|
@ -13,17 +13,18 @@
|
|||
To completely disable a check, just comment it out or delete it from the file.
|
||||
To suppress certain violations please review suppression filters.
|
||||
|
||||
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
|
||||
Authors: Max Vetrenko, Mauryan Kansara, Ruslan Diachenko, Roman Ivanov.
|
||||
-->
|
||||
|
||||
<module name = "Checker">
|
||||
<module name="Checker">
|
||||
|
||||
<property name="charset" value="UTF-8"/>
|
||||
|
||||
<property name="severity" value="error"/>
|
||||
|
||||
<property name="fileExtensions" value="java, properties, xml"/>
|
||||
<!-- Excludes all 'module-info.java' files -->
|
||||
<!-- See https://checkstyle.org/config_filefilters.html -->
|
||||
<!-- See https://checkstyle.org/filefilters/index.html -->
|
||||
<module name="BeforeExecutionExclusionFileFilter">
|
||||
<property name="fileNamePattern" value="module\-info\.java$"/>
|
||||
</module>
|
||||
|
@ -34,9 +35,16 @@
|
|||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- https://checkstyle.org/filters/suppresswithnearbytextfilter.html -->
|
||||
<!--<module name="SuppressWithNearbyTextFilter">
|
||||
<property name="nearbyTextPattern"
|
||||
value="CHECKSTYLE.SUPPRESS\: (\w+) for ([+-]\d+) lines"/>
|
||||
<property name="checkPattern" value="$1"/>
|
||||
<property name="lineRange" value="$2"/>
|
||||
</module>-->
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.org/config_whitespace.html -->
|
||||
<!-- See http://checkstyle.org/checks/whitespace/index.html -->
|
||||
<module name="FileTabCharacter">
|
||||
<property name="eachLine" value="true"/>
|
||||
</module>
|
||||
|
@ -52,7 +60,7 @@
|
|||
<module name="TreeWalker">
|
||||
<!-- needed for SuppressWarningsFilter -->
|
||||
<module name="SuppressWarningsHolder" />
|
||||
|
||||
|
||||
<module name="SuppressWarnings">
|
||||
<property name="id" value="checkstyle:suppresswarnings"/>
|
||||
</module>
|
||||
|
@ -69,48 +77,68 @@
|
|||
<module name="IllegalTokenText">
|
||||
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
|
||||
<property name="format"
|
||||
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
|
||||
<property name="message"
|
||||
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
|
||||
</module>
|
||||
<module name="AvoidEscapedUnicodeCharacters">
|
||||
<property name="allowEscapesForControlCharacters" value="true"/>
|
||||
<property name="allowByTailComment" value="true"/>
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
</module>
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="OneTopLevelClass"/>
|
||||
<module name="NoLineWrap">
|
||||
<property name="tokens" value="PACKAGE_DEF, IMPORT, STATIC_IMPORT"/>
|
||||
</module>
|
||||
<module name="EmptyBlock">
|
||||
<property name="option" value="TEXT"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||
</module>
|
||||
<module name="NeedBraces">
|
||||
<property name="tokens"
|
||||
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
|
||||
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE"/>
|
||||
</module>
|
||||
<module name="LeftCurly">
|
||||
<property name="id" value="LeftCurlyEol"/>
|
||||
<property name="tokens"
|
||||
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
|
||||
INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
|
||||
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
|
||||
OBJBLOCK, STATIC_INIT"/>
|
||||
value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
|
||||
INTERFACE_DEF, LITERAL_CATCH,
|
||||
LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF,
|
||||
LITERAL_WHILE, METHOD_DEF,
|
||||
OBJBLOCK, STATIC_INIT, RECORD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="LeftCurly">
|
||||
<property name="id" value="LeftCurlyNl"/>
|
||||
<property name="option" value="nl"/>
|
||||
<property name="tokens"
|
||||
value=" LITERAL_DEFAULT"/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<!-- LITERAL_DEFAULT are reused in SWITCH_RULE -->
|
||||
<property name="id" value="LeftCurlyNl"/>
|
||||
<property name="query" value="//SWITCH_RULE/SLIST"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlySame"/>
|
||||
<property name="tokens"
|
||||
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
|
||||
value="LITERAL_IF, LITERAL_ELSE,
|
||||
LITERAL_DO"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="option" value="alone"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
|
||||
INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF"/>
|
||||
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT,
|
||||
INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF,
|
||||
COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<!-- suppression is required till https://github.com/checkstyle/checkstyle/issues/7541 -->
|
||||
<property name="id" value="RightCurlyAlone"/>
|
||||
<property name="query" value="//RCURLY[parent::SLIST[count(./*)=1]
|
||||
or preceding-sibling::*[last()][self::LCURLY]]"/>
|
||||
</module>
|
||||
<module name="WhitespaceAfter">
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, TYPECAST, LITERAL_IF, LITERAL_ELSE,
|
||||
LITERAL_WHILE, LITERAL_DO, LITERAL_FOR, DO_WHILE"/>
|
||||
</module>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" value="true"/>
|
||||
|
@ -118,18 +146,35 @@
|
|||
<property name="allowEmptyMethods" value="true"/>
|
||||
<property name="allowEmptyTypes" value="true"/>
|
||||
<property name="allowEmptyLoops" value="true"/>
|
||||
<!--<property name="allowEmptySwitchBlockStatements" value="true"/>-->
|
||||
<property name="ignoreEnhancedForColon" value="false"/>
|
||||
<property name="tokens"
|
||||
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
|
||||
BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAMBDA, LAND,
|
||||
LCURLY, LE, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
|
||||
LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SWITCH, LITERAL_SYNCHRONIZED,
|
||||
LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
|
||||
NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
|
||||
SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT, TYPE_EXTENSION_AND"/>
|
||||
value="ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR,
|
||||
BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, DO_WHILE, EQUAL, GE, GT, LAND,
|
||||
LCURLY, LE, LITERAL_DO, LITERAL_ELSE,
|
||||
LITERAL_FOR, LITERAL_IF,
|
||||
LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN,
|
||||
NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL, SLIST, SL_ASSIGN, SR,
|
||||
SR_ASSIGN, STAR, STAR_ASSIGN, LITERAL_ASSERT,
|
||||
TYPE_EXTENSION_AND"/>
|
||||
<message key="ws.notFollowed"
|
||||
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
|
||||
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks
|
||||
may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
|
||||
<message key="ws.notPreceded"
|
||||
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="WhitespaceAround"/>
|
||||
<property name="query" value="//*[self::LITERAL_IF or self::LITERAL_ELSE or self::STATIC_INIT
|
||||
or self::LITERAL_TRY or self::LITERAL_CATCH]/SLIST[count(./*)=1]
|
||||
| //*[self::STATIC_INIT or self::LITERAL_TRY or self::LITERAL_IF]
|
||||
//*[self::RCURLY][parent::SLIST[count(./*)=1]]"/>
|
||||
</module>
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="\{[ ]+\}"/>
|
||||
<property name="message" value="Empty blocks should have no spaces. Empty blocks
|
||||
may only be represented as '{}' when not part of a
|
||||
multi-block statement (4.1.3)"/>
|
||||
</module>
|
||||
<module name="OneStatementPerLine"/>
|
||||
<module name="MultipleVariableDeclarations"/>
|
||||
|
@ -140,8 +185,9 @@
|
|||
<module name="ModifierOrder"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="tokens"
|
||||
value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||
value="PACKAGE_DEF, IMPORT, STATIC_IMPORT, CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
STATIC_INIT, INSTANCE_INIT, METHOD_DEF, CTOR_DEF, VARIABLE_DEF, RECORD_DEF,
|
||||
COMPACT_CTOR_DEF"/>
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
|
@ -155,13 +201,13 @@
|
|||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
|
||||
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/259 -->
|
||||
<property name="id" value="SeparatorWrapEllipsis"/>
|
||||
<property name="tokens" value="ELLIPSIS"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
|
||||
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/258 -->
|
||||
<property name="id" value="SeparatorWrapArrayDeclarator"/>
|
||||
<property name="tokens" value="ARRAY_DECLARATOR"/>
|
||||
<property name="option" value="EOL"/>
|
||||
|
@ -174,22 +220,23 @@
|
|||
<module name="PackageName">
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="TypeName">
|
||||
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF"/>
|
||||
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
ANNOTATION_DEF, RECORD_DEF"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Member name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LambdaParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
|
@ -199,38 +246,53 @@
|
|||
<module name="CatchParameterName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="LocalVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="PatternVariableName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Pattern variable name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="ClassTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Class type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="RecordComponentName">
|
||||
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Record component name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="RecordTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Record type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MethodTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Method type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="InterfaceTypeParameterName">
|
||||
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="NoFinalizer"/>
|
||||
<module name="GenericWhitespace">
|
||||
<message key="ws.followed"
|
||||
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
|
||||
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
|
||||
<message key="ws.preceded"
|
||||
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
|
||||
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
|
||||
<message key="ws.illegalFollow"
|
||||
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
|
||||
<message key="ws.notPreceded"
|
||||
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
|
||||
</module>
|
||||
<module name="Indentation">
|
||||
<property name="basicOffset" value="4"/>
|
||||
|
@ -240,44 +302,62 @@
|
|||
<property name="lineWrappingIndentation" value="4"/>
|
||||
<property name="arrayInitIndent" value="4"/>
|
||||
</module>
|
||||
<!-- Suppression for block code until we find a way to detect them properly
|
||||
until https://github.com/checkstyle/checkstyle/issues/15769 -->
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="Indentation"/>
|
||||
<property name="query" value="//SLIST[not(parent::CASE_GROUP)]/SLIST
|
||||
| //SLIST[not(parent::CASE_GROUP)]/SLIST/RCURLY"/>
|
||||
</module>
|
||||
<module name="AbbreviationAsWordInName">
|
||||
<property name="ignoreFinal" value="true"/>
|
||||
<property name="allowedAbbreviations" value="API" />
|
||||
<property name="allowedAbbreviationLength" value="1"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
|
||||
PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF"/>
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, ANNOTATION_DEF, ANNOTATION_FIELD_DEF,
|
||||
PARAMETER_DEF, VARIABLE_DEF, METHOD_DEF, PATTERN_VARIABLE_DEF, RECORD_DEF,
|
||||
RECORD_COMPONENT_DEF"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBeforeCaseDefaultColon"/>
|
||||
<module name="OverloadMethodsDeclarationOrder"/>
|
||||
<!--<module name="ConstructorsDeclarationGrouping"/>-->
|
||||
<module name="VariableDeclarationUsageDistance"/>
|
||||
<module name="CustomImportOrder">
|
||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||
<property name="separateLineBetweenGroups" value="true"/>
|
||||
<property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
|
||||
<property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
|
||||
</module>
|
||||
<module name="MethodParamPad">
|
||||
<property name="tokens"
|
||||
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF,
|
||||
value="CTOR_DEF, LITERAL_NEW, METHOD_CALL, METHOD_DEF,
|
||||
SUPER_CTOR_CALL, ENUM_CONSTANT_DEF"/>
|
||||
</module>
|
||||
<module name="NoWhitespaceBefore">
|
||||
<property name="tokens"
|
||||
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
|
||||
value="COMMA, SEMI, POST_INC, POST_DEC, DOT,
|
||||
LABELED_STAT, METHOD_REF"/>
|
||||
<property name="allowLineBreaks" value="true"/>
|
||||
</module>
|
||||
<module name="ParenPad">
|
||||
<property name="tokens"
|
||||
value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_CALL, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
|
||||
EXPR, LITERAL_CATCH, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
|
||||
LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_WHILE, METHOD_CALL,
|
||||
METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL, LAMBDA"/>
|
||||
value="ANNOTATION, ANNOTATION_FIELD_DEF, CTOR_DEF, DOT, ENUM_CONSTANT_DEF,
|
||||
EXPR, LITERAL_DO, LITERAL_FOR, LITERAL_IF, LITERAL_NEW,
|
||||
LITERAL_WHILE, METHOD_CALL,
|
||||
METHOD_DEF, QUESTION, RESOURCE_SPECIFICATION, SUPER_CTOR_CALL"/>
|
||||
</module>
|
||||
<module name="OperatorWrap">
|
||||
<property name="option" value="NL"/>
|
||||
<property name="tokens"
|
||||
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
|
||||
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
|
||||
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR,
|
||||
LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF,
|
||||
TYPE_EXTENSION_AND "/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationMostCases"/>
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
|
||||
<property name="allowSamelineMultipleAnnotations" value="true"/>
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF,
|
||||
RECORD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="AnnotationLocation">
|
||||
<property name="id" value="AnnotationLocationVariables"/>
|
||||
|
@ -289,46 +369,83 @@
|
|||
<module name="JavadocTagContinuationIndentation"/>
|
||||
<module name="SummaryJavadoc">
|
||||
<property name="forbiddenSummaryFragments"
|
||||
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
|
||||
</module>
|
||||
<module name="JavadocParagraph"/>
|
||||
<module name="JavadocParagraph">
|
||||
</module>
|
||||
<module name="RequireEmptyLineBeforeBlockTagGroup"/>
|
||||
<module name="AtclauseOrder">
|
||||
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||
<property name="target"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
|
||||
</module>
|
||||
<module name="JavadocMethod">
|
||||
<property name="accessModifiers" value="public"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
<property name="allowedAnnotations" value="Override, Test"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF, COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="MissingJavadocMethod">
|
||||
<property name="scope" value="public"/>
|
||||
<property name="minLineCount" value="2"/>
|
||||
<property name="allowMissingPropertyJavadoc" value="true"/>
|
||||
<property name="allowedAnnotations" value="Override, Test"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF"/>
|
||||
<property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF,
|
||||
COMPACT_CTOR_DEF"/>
|
||||
</module>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="MissingJavadocMethod"/>
|
||||
<property name="query" value="//*[self::METHOD_DEF or self::CTOR_DEF
|
||||
or self::ANNOTATION_FIELD_DEF or self::COMPACT_CTOR_DEF]
|
||||
[ancestor::*[self::INTERFACE_DEF or self::CLASS_DEF
|
||||
or self::RECORD_DEF or self::ENUM_DEF]
|
||||
[not(./MODIFIERS/LITERAL_PUBLIC)]]"/>
|
||||
</module>
|
||||
<module name="MissingJavadocType">
|
||||
<property name="scope" value="protected"/>
|
||||
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
<property name="tokens"
|
||||
value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
|
||||
RECORD_DEF, ANNOTATION_DEF"/>
|
||||
<property name="excludeScope" value="nothing"/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||
value="Method name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="SingleLineJavadoc">
|
||||
<property name="ignoreInlineTags" value="false"/>
|
||||
<module name="SuppressionXpathSingleFilter">
|
||||
<property name="checks" value="MethodName"/>
|
||||
<property name="query" value="//METHOD_DEF[
|
||||
./MODIFIERS/ANNOTATION//IDENT[contains(@text, 'Test')]
|
||||
]/IDENT"/>
|
||||
<property name="message" value="'[a-z][a-z0-9][a-zA-Z0-9]*(?:_[a-z][a-z0-9][a-zA-Z0-9]*)*'"/>
|
||||
</module>
|
||||
<module name="SingleLineJavadoc"/>
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="expected"/>
|
||||
</module>
|
||||
<module name="CommentsIndentation">
|
||||
<property name="tokens" value="SINGLE_LINE_COMMENT, BLOCK_COMMENT_BEGIN"/>
|
||||
</module>
|
||||
<!-- https://checkstyle.org/filters/suppressionxpathfilter.html -->
|
||||
<module name="SuppressionXpathFilter">
|
||||
<property name="file" value="${org.checkstyle.google.suppressionxpathfilter.config}"
|
||||
default="checkstyle-xpath-suppressions.xml" />
|
||||
<property name="optional" value="true"/>
|
||||
</module>
|
||||
<module name="SuppressWarningsHolder" />
|
||||
<module name="SuppressionCommentFilter">
|
||||
<property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)" />
|
||||
<property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)" />
|
||||
<property name="checkFormat" value="$1" />
|
||||
</module>
|
||||
<module name="SuppressWithNearbyCommentFilter">
|
||||
<property name="commentFormat" value="CHECKSTYLE.SUPPRESS\: ([\w\|]+)"/>
|
||||
<!-- $1 refers to the first match group in the regex defined in commentFormat -->
|
||||
<property name="checkFormat" value="$1"/>
|
||||
<!-- The check is suppressed in the next line of code after the comment -->
|
||||
<property name="influenceFormat" value="1"/>
|
||||
</module>
|
||||
</module>
|
||||
</module>
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
set -euf
|
||||
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||
|
||||
# OS specific support.
|
||||
native_path() { printf %s\\n "$1"; }
|
||||
case "$(uname)" in
|
||||
CYGWIN* | MINGW*)
|
||||
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||
native_path() { cygpath --path --windows "$1"; }
|
||||
;;
|
||||
esac
|
||||
|
||||
# set JAVACMD and JAVACCMD
|
||||
set_java_home() {
|
||||
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||
if [ -n "${JAVA_HOME-}" ]; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||
|
||||
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(
|
||||
'set' +e
|
||||
'unset' -f command 2>/dev/null
|
||||
'command' -v java
|
||||
)" || :
|
||||
JAVACCMD="$(
|
||||
'set' +e
|
||||
'unset' -f command 2>/dev/null
|
||||
'command' -v javac
|
||||
)" || :
|
||||
|
||||
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# hash string like Java String::hashCode
|
||||
hash_string() {
|
||||
str="${1:-}" h=0
|
||||
while [ -n "$str" ]; do
|
||||
char="${str%"${str#?}"}"
|
||||
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||
str="${str#?}"
|
||||
done
|
||||
printf %x\\n $h
|
||||
}
|
||||
|
||||
verbose() { :; }
|
||||
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||
|
||||
die() {
|
||||
printf %s\\n "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
trim() {
|
||||
# MWRAPPER-139:
|
||||
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||
# Needed for removing poorly interpreted newline sequences when running in more
|
||||
# exotic environments such as mingw bash on Windows.
|
||||
printf "%s" "${1}" | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||
while IFS="=" read -r key value; do
|
||||
case "${key-}" in
|
||||
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||
esac
|
||||
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||
|
||||
case "${distributionUrl##*/}" in
|
||||
maven-mvnd-*bin.*)
|
||||
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||
*)
|
||||
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||
distributionPlatform=linux-amd64
|
||||
;;
|
||||
esac
|
||||
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||
;;
|
||||
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||
esac
|
||||
|
||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||
distributionUrlName="${distributionUrl##*/}"
|
||||
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||
|
||||
exec_maven() {
|
||||
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||
}
|
||||
|
||||
if [ -d "$MAVEN_HOME" ]; then
|
||||
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||
exec_maven "$@"
|
||||
fi
|
||||
|
||||
case "${distributionUrl-}" in
|
||||
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||
esac
|
||||
|
||||
# prepare tmp dir
|
||||
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||
trap clean HUP INT TERM EXIT
|
||||
else
|
||||
die "cannot create temp dir"
|
||||
fi
|
||||
|
||||
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||
|
||||
# Download and Install Apache Maven
|
||||
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||
verbose "Downloading from: $distributionUrl"
|
||||
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
|
||||
# select .zip or .tar.gz
|
||||
if ! command -v unzip >/dev/null; then
|
||||
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||
distributionUrlName="${distributionUrl##*/}"
|
||||
fi
|
||||
|
||||
# verbose opt
|
||||
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||
|
||||
# normalize http auth
|
||||
case "${MVNW_PASSWORD:+has-password}" in
|
||||
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||
esac
|
||||
|
||||
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||
verbose "Found wget ... using wget"
|
||||
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||
verbose "Found curl ... using curl"
|
||||
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||
elif set_java_home; then
|
||||
verbose "Falling back to use Java to download"
|
||||
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
cat >"$javaSource" <<-END
|
||||
public class Downloader extends java.net.Authenticator
|
||||
{
|
||||
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||
}
|
||||
public static void main( String[] args ) throws Exception
|
||||
{
|
||||
setDefault( new Downloader() );
|
||||
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||
}
|
||||
}
|
||||
END
|
||||
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||
verbose " - Compiling Downloader.java ..."
|
||||
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||
verbose " - Running Downloader.java ..."
|
||||
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||
fi
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
if [ -n "${distributionSha256Sum-}" ]; then
|
||||
distributionSha256Result=false
|
||||
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
elif command -v sha256sum >/dev/null; then
|
||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||
distributionSha256Result=true
|
||||
fi
|
||||
elif command -v shasum >/dev/null; then
|
||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||
distributionSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ $distributionSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# unzip and move
|
||||
if command -v unzip >/dev/null; then
|
||||
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||
else
|
||||
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||
fi
|
||||
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||
|
||||
clean || :
|
||||
exec_maven "$@"
|
|
@ -0,0 +1,149 @@
|
|||
<# : batch portion
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||
@SET __MVNW_CMD__=
|
||||
@SET __MVNW_ERROR__=
|
||||
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||
@SET PSModulePath=
|
||||
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||
)
|
||||
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||
@SET __MVNW_PSMODULEP_SAVE=
|
||||
@SET __MVNW_ARG0_NAME__=
|
||||
@SET MVNW_USERNAME=
|
||||
@SET MVNW_PASSWORD=
|
||||
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||
@GOTO :EOF
|
||||
: end batch / begin powershell #>
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
if ($env:MVNW_VERBOSE -eq "true") {
|
||||
$VerbosePreference = "Continue"
|
||||
}
|
||||
|
||||
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||
if (!$distributionUrl) {
|
||||
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||
}
|
||||
|
||||
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||
"maven-mvnd-*" {
|
||||
$USE_MVND = $true
|
||||
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||
$MVN_CMD = "mvnd.cmd"
|
||||
break
|
||||
}
|
||||
default {
|
||||
$USE_MVND = $false
|
||||
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||
if ($env:MVNW_REPOURL) {
|
||||
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||
}
|
||||
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||
if ($env:MAVEN_USER_HOME) {
|
||||
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||
}
|
||||
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||
|
||||
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||
exit $?
|
||||
}
|
||||
|
||||
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||
}
|
||||
|
||||
# prepare tmp dir
|
||||
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||
trap {
|
||||
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||
}
|
||||
}
|
||||
|
||||
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||
|
||||
# Download and Install Apache Maven
|
||||
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||
Write-Verbose "Downloading from: $distributionUrl"
|
||||
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||
|
||||
$webclient = New-Object System.Net.WebClient
|
||||
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||
}
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||
if ($distributionSha256Sum) {
|
||||
if ($USE_MVND) {
|
||||
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||
}
|
||||
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||
}
|
||||
}
|
||||
|
||||
# unzip and move
|
||||
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||
try {
|
||||
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||
} catch {
|
||||
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||
Write-Error "fail to move MAVEN_HOME"
|
||||
}
|
||||
} finally {
|
||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||
}
|
||||
|
||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit d4a9a910946eded57cf82d6fd4921785a5e64c2b
|
111
spec_finder.py
111
spec_finder.py
|
@ -1,111 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
import urllib.request
|
||||
import json
|
||||
import re
|
||||
import difflib
|
||||
import os
|
||||
import sys
|
||||
|
||||
def _demarkdown(t):
|
||||
return t.replace('**', '').replace('`', '').replace('"', '')
|
||||
|
||||
def get_spec(force_refresh=False):
|
||||
spec_path = './specification.json'
|
||||
data = ""
|
||||
if os.path.exists(spec_path) and not force_refresh:
|
||||
with open(spec_path) as f:
|
||||
data = ''.join(f.readlines())
|
||||
else:
|
||||
# TODO: Status code check
|
||||
spec_response = urllib.request.urlopen('https://raw.githubusercontent.com/open-feature/spec/main/specification.json')
|
||||
raw = []
|
||||
for i in spec_response.readlines():
|
||||
raw.append(i.decode('utf-8'))
|
||||
data = ''.join(raw)
|
||||
with open(spec_path, 'w') as f:
|
||||
f.write(data)
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
def main(refresh_spec=False, diff_output=False, limit_numbers=None):
|
||||
actual_spec = get_spec(refresh_spec)
|
||||
|
||||
spec_map = {}
|
||||
for entry in actual_spec['rules']:
|
||||
number = re.search('[\d.]+', entry['id']).group()
|
||||
if 'requirement' in entry['machine_id']:
|
||||
spec_map[number] = _demarkdown(entry['content'])
|
||||
|
||||
if len(entry['children']) > 0:
|
||||
for ch in entry['children']:
|
||||
number = re.search('[\d.]+', ch['id']).group()
|
||||
if 'requirement' in ch['machine_id']:
|
||||
spec_map[number] = _demarkdown(ch['content'])
|
||||
|
||||
java_specs = {}
|
||||
missing = set(spec_map.keys())
|
||||
|
||||
|
||||
import os
|
||||
for root, dirs, files in os.walk(".", topdown=False):
|
||||
for name in files:
|
||||
F = os.path.join(root, name)
|
||||
if '.java' not in name:
|
||||
continue
|
||||
with open(F) as f:
|
||||
data = ''.join(f.readlines())
|
||||
|
||||
for match in re.findall('@Specification\((?P<innards>.*?)"\)', data.replace('\n', ''), re.MULTILINE | re.DOTALL):
|
||||
number = re.findall('number\s*=\s*"(.*?)"', match)[0]
|
||||
|
||||
if number in missing:
|
||||
missing.remove(number)
|
||||
text_with_concat_chars = re.findall('text\s*=\s*(.*)', match)
|
||||
try:
|
||||
# We have to match for ") to capture text with parens inside, so we add the trailing " back in.
|
||||
text = _demarkdown(eval(''.join(text_with_concat_chars) + '"'))
|
||||
entry = java_specs[number] = {
|
||||
'number': number,
|
||||
'text': text,
|
||||
}
|
||||
except:
|
||||
print(f"Skipping {match} b/c we couldn't parse it")
|
||||
|
||||
bad_num = len(missing)
|
||||
for number, entry in java_specs.items():
|
||||
if limit_numbers is not None and len(limit_numbers) > 0 and number not in limit_numbers:
|
||||
continue
|
||||
if number in spec_map:
|
||||
txt = entry['text']
|
||||
if txt == spec_map[number]:
|
||||
# print(f'{number} is good')
|
||||
continue
|
||||
else:
|
||||
print(f"{number} is bad")
|
||||
bad_num += 1
|
||||
if diff_output:
|
||||
print(number + '\n' + '\n'.join([li for li in difflib.ndiff([txt], [spec_map[number]]) if not li.startswith(' ')]))
|
||||
continue
|
||||
|
||||
print(f"{number} is defined in our tests, but couldn't find it in the spec")
|
||||
print("")
|
||||
|
||||
if len(missing) > 0:
|
||||
print('In the spec, but not in our tests: ')
|
||||
for m in missing:
|
||||
print(f" {m}: {spec_map[m]}")
|
||||
|
||||
sys.exit(bad_num)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='Parse the spec to make sure our tests cover it')
|
||||
parser.add_argument('--refresh-spec', action='store_true', help='Re-downloads the spec')
|
||||
parser.add_argument('--diff-output', action='store_true', help='print the text differences')
|
||||
parser.add_argument('specific_numbers', metavar='num', type=str, nargs='*',
|
||||
help='limit this to specific numbers')
|
||||
|
||||
args = parser.parse_args()
|
||||
main(refresh_spec=args.refresh_spec, diff_output=args.diff_output, limit_numbers=args.specific_numbers)
|
|
@ -1,19 +1,36 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" })
|
||||
@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
|
||||
@EqualsAndHashCode
|
||||
abstract class AbstractStructure implements Structure {
|
||||
|
||||
protected final Map<String, Value> attributes;
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return attributes == null || attributes.isEmpty();
|
||||
}
|
||||
|
||||
AbstractStructure() {
|
||||
this.attributes = new HashMap<>();
|
||||
}
|
||||
|
||||
AbstractStructure(Map<String, Value> attributes) {
|
||||
this.attributes = new HashMap<>(attributes);
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable representation of the internal attribute map.
|
||||
*
|
||||
* @return immutable map
|
||||
*/
|
||||
public Map<String, Value> asUnmodifiableMap() {
|
||||
return Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,12 +40,11 @@ abstract class AbstractStructure implements Structure {
|
|||
*/
|
||||
@Override
|
||||
public Map<String, Object> asObjectMap() {
|
||||
return attributes
|
||||
.entrySet()
|
||||
.stream()
|
||||
return attributes.entrySet().stream()
|
||||
// custom collector, workaround for Collectors.toMap in JDK8
|
||||
// https://bugs.openjdk.org/browse/JDK-8148463
|
||||
.collect(HashMap::new,
|
||||
.collect(
|
||||
HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(), convertValue(entry.getValue())),
|
||||
HashMap::putAll);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -2,29 +2,34 @@ package dev.openfeature.sdk;
|
|||
|
||||
/**
|
||||
* This is a common interface between the evaluation results that providers return and what is given to the end users.
|
||||
*
|
||||
* @param <T> The type of flag being evaluated.
|
||||
*/
|
||||
public interface BaseEvaluation<T> {
|
||||
/**
|
||||
* Returns the resolved value of the evaluation.
|
||||
*
|
||||
* @return {T} the resolve value
|
||||
*/
|
||||
T getValue();
|
||||
|
||||
/**
|
||||
* Returns an identifier for this value, if applicable.
|
||||
*
|
||||
* @return {String} value identifier
|
||||
*/
|
||||
String getVariant();
|
||||
|
||||
/**
|
||||
* Describes how we came to the value that we're returning.
|
||||
*
|
||||
* @return {Reason}
|
||||
*/
|
||||
String getReason();
|
||||
|
||||
/**
|
||||
* The error code, if applicable. Should only be set when the Reason is ERROR.
|
||||
*
|
||||
* @return {ErrorCode}
|
||||
*/
|
||||
ErrorCode getErrorCode();
|
||||
|
@ -32,6 +37,7 @@ public interface BaseEvaluation<T> {
|
|||
/**
|
||||
* The error message (usually from exception.getMessage()), if applicable.
|
||||
* Should only be set when the Reason is ERROR.
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
String getErrorMessage();
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic
|
||||
* to the lifecycle of flag evaluation.
|
||||
*
|
||||
* @see Hook
|
||||
*/
|
||||
public interface BooleanHook extends Hook<Boolean> {
|
||||
|
||||
|
|
|
@ -5,17 +5,19 @@ import java.util.List;
|
|||
/**
|
||||
* Interface used to resolve flags of varying types.
|
||||
*/
|
||||
public interface Client extends Features, EventBus<Client> {
|
||||
Metadata getMetadata();
|
||||
public interface Client extends Features, Tracking, EventBus<Client> {
|
||||
ClientMetadata getMetadata();
|
||||
|
||||
/**
|
||||
* Return an optional client-level evaluation context.
|
||||
*
|
||||
* @return {@link EvaluationContext}
|
||||
*/
|
||||
EvaluationContext getEvaluationContext();
|
||||
|
||||
/**
|
||||
* Set the client-level evaluation context.
|
||||
*
|
||||
* @param ctx Client level context.
|
||||
*/
|
||||
Client setEvaluationContext(EvaluationContext ctx);
|
||||
|
@ -30,7 +32,15 @@ public interface Client extends Features, EventBus<Client> {
|
|||
|
||||
/**
|
||||
* Fetch the hooks associated to this client.
|
||||
*
|
||||
* @return A list of {@link Hook}s.
|
||||
*/
|
||||
List<Hook> getHooks();
|
||||
|
||||
/**
|
||||
* Returns the current state of the associated provider.
|
||||
*
|
||||
* @return the provider state
|
||||
*/
|
||||
ProviderState getProviderState();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
/**
|
||||
* Metadata specific to an OpenFeature {@code Client}.
|
||||
*/
|
||||
public interface ClientMetadata {
|
||||
String getDomain();
|
||||
|
||||
@Deprecated
|
||||
// this is here for compatibility with getName() exposed from {@link Metadata}
|
||||
default String getName() {
|
||||
return getDomain();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic
|
||||
* to the lifecycle of flag evaluation.
|
||||
*
|
||||
* @see Hook
|
||||
*/
|
||||
public interface DoubleHook extends Hook<Double> {
|
||||
|
||||
|
@ -9,4 +12,4 @@ public interface DoubleHook extends Hook<Double> {
|
|||
default boolean supportsFlagValueType(FlagValueType flagValueType) {
|
||||
return FlagValueType.DOUBLE == flagValueType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,5 +2,12 @@ package dev.openfeature.sdk;
|
|||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
public enum ErrorCode {
|
||||
PROVIDER_NOT_READY, FLAG_NOT_FOUND, PARSE_ERROR, TYPE_MISMATCH, TARGETING_KEY_MISSING, INVALID_CONTEXT, GENERAL
|
||||
PROVIDER_NOT_READY,
|
||||
FLAG_NOT_FOUND,
|
||||
PARSE_ERROR,
|
||||
TYPE_MISMATCH,
|
||||
TARGETING_KEY_MISSING,
|
||||
INVALID_CONTEXT,
|
||||
GENERAL,
|
||||
PROVIDER_FATAL
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The EvaluationContext is a container for arbitrary contextual data
|
||||
* that can be used as a basis for dynamic evaluation.
|
||||
|
@ -19,4 +23,41 @@ public interface EvaluationContext extends Structure {
|
|||
* @return resulting merged context
|
||||
*/
|
||||
EvaluationContext merge(EvaluationContext overridingContext);
|
||||
|
||||
/**
|
||||
* Recursively merges the overriding map into the base Value map.
|
||||
* The base map is mutated, the overriding map is not.
|
||||
* Null maps will cause no-op.
|
||||
*
|
||||
* @param newStructure function to create the right structure(s) for Values
|
||||
* @param base base map to merge
|
||||
* @param overriding overriding map to merge
|
||||
*/
|
||||
static void mergeMaps(
|
||||
Function<Map<String, Value>, Structure> newStructure,
|
||||
Map<String, Value> base,
|
||||
Map<String, Value> overriding) {
|
||||
|
||||
if (base == null) {
|
||||
return;
|
||||
}
|
||||
if (overriding == null || overriding.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Entry<String, Value> overridingEntry : overriding.entrySet()) {
|
||||
String key = overridingEntry.getKey();
|
||||
if (overridingEntry.getValue().isStructure()
|
||||
&& base.containsKey(key)
|
||||
&& base.get(key).isStructure()) {
|
||||
Structure mergedValue = base.get(key).asStructure();
|
||||
Structure overridingValue = overridingEntry.getValue().asStructure();
|
||||
Map<String, Value> newMap = mergedValue.asMap();
|
||||
mergeMaps(newStructure, newMap, overridingValue.asUnmodifiableMap());
|
||||
base.put(key, new Value(newStructure.apply(newMap)));
|
||||
} else {
|
||||
base.put(key, overridingEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -6,38 +6,38 @@ import java.util.function.Consumer;
|
|||
* Interface for attaching event handlers.
|
||||
*/
|
||||
public interface EventBus<T> {
|
||||
|
||||
|
||||
/**
|
||||
* Add a handler for the {@link ProviderEvent#PROVIDER_READY} event.
|
||||
* Shorthand for {@link #on(ProviderEvent, Consumer)}
|
||||
*
|
||||
*
|
||||
* @param handler behavior to add with this event
|
||||
* @return this
|
||||
*/
|
||||
T onProviderReady(Consumer<EventDetails> handler);
|
||||
|
||||
|
||||
/**
|
||||
* Add a handler for the {@link ProviderEvent#PROVIDER_CONFIGURATION_CHANGED} event.
|
||||
* Shorthand for {@link #on(ProviderEvent, Consumer)}
|
||||
*
|
||||
*
|
||||
* @param handler behavior to add with this event
|
||||
* @return this
|
||||
*/
|
||||
T onProviderConfigurationChanged(Consumer<EventDetails> handler);
|
||||
|
||||
|
||||
/**
|
||||
* Add a handler for the {@link ProviderEvent#PROVIDER_STALE} event.
|
||||
* Shorthand for {@link #on(ProviderEvent, Consumer)}
|
||||
*
|
||||
*
|
||||
* @param handler behavior to add with this event
|
||||
* @return this
|
||||
*/
|
||||
T onProviderError(Consumer<EventDetails> handler);
|
||||
|
||||
|
||||
/**
|
||||
* Add a handler for the {@link ProviderEvent#PROVIDER_ERROR} event.
|
||||
* Shorthand for {@link #on(ProviderEvent, Consumer)}
|
||||
*
|
||||
*
|
||||
* @param handler behavior to add with this event
|
||||
* @return this
|
||||
*/
|
||||
|
@ -45,18 +45,18 @@ public interface EventBus<T> {
|
|||
|
||||
/**
|
||||
* Add a handler for the specified {@link ProviderEvent}.
|
||||
*
|
||||
* @param event event type
|
||||
*
|
||||
* @param event event type
|
||||
* @param handler behavior to add with this event
|
||||
* @return this
|
||||
*/
|
||||
T on(ProviderEvent event, Consumer<EventDetails> handler);
|
||||
|
||||
|
||||
/**
|
||||
* Remove the previously attached handler by reference.
|
||||
* If the handler doesn't exists, no-op.
|
||||
*
|
||||
* @param event event type
|
||||
*
|
||||
* @param event event type
|
||||
* @param handler to be removed
|
||||
* @return this
|
||||
*/
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* The details of a particular event.
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@SuperBuilder(toBuilder = true)
|
||||
public class EventDetails extends ProviderEventDetails {
|
||||
private String clientName;
|
||||
private String domain;
|
||||
private String providerName;
|
||||
|
||||
static EventDetails fromProviderEventDetails(ProviderEventDetails providerEventDetails, String providerName) {
|
||||
return EventDetails.fromProviderEventDetails(providerEventDetails, providerName, null);
|
||||
return fromProviderEventDetails(providerEventDetails, providerName, null);
|
||||
}
|
||||
|
||||
static EventDetails fromProviderEventDetails(
|
||||
ProviderEventDetails providerEventDetails,
|
||||
String providerName,
|
||||
String clientName) {
|
||||
return EventDetails.builder()
|
||||
.clientName(clientName)
|
||||
ProviderEventDetails providerEventDetails, String providerName, String domain) {
|
||||
return builder()
|
||||
.domain(domain)
|
||||
.providerName(providerName)
|
||||
.flagsChanged(providerEventDetails.getFlagsChanged())
|
||||
.eventMetadata(providerEventDetails.getEventMetadata())
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.internal.TriConsumer;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Abstract EventProvider. Providers must extend this class to support events.
|
||||
|
@ -14,23 +18,23 @@ import dev.openfeature.sdk.internal.TriConsumer;
|
|||
*
|
||||
* @see FeatureProvider
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class EventProvider implements FeatureProvider {
|
||||
private EventProviderListener eventProviderListener;
|
||||
private final ExecutorService emitterExecutor = Executors.newCachedThreadPool();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public abstract ProviderState getState();
|
||||
void setEventProviderListener(EventProviderListener eventProviderListener) {
|
||||
this.eventProviderListener = eventProviderListener;
|
||||
}
|
||||
|
||||
private TriConsumer<EventProvider, ProviderEvent, ProviderEventDetails> onEmit = null;
|
||||
|
||||
/**
|
||||
* "Attach" this EventProvider to an SDK, which allows events to propagate from this provider.
|
||||
* No-op if the same onEmit is already attached.
|
||||
* No-op if the same onEmit is already attached.
|
||||
*
|
||||
* @param onEmit the function to run when a provider emits events.
|
||||
* @throws IllegalStateException if attempted to bind a new emitter for already bound provider
|
||||
*
|
||||
*/
|
||||
void attach(TriConsumer<EventProvider, ProviderEvent, ProviderEventDetails> onEmit) {
|
||||
if (this.onEmit != null && this.onEmit != onEmit) {
|
||||
|
@ -48,56 +52,96 @@ public abstract class EventProvider implements FeatureProvider {
|
|||
this.onEmit = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the event emitter executor and block until either termination has completed
|
||||
* or timeout period has elapsed.
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
emitterExecutor.shutdown();
|
||||
try {
|
||||
if (!emitterExecutor.awaitTermination(EventSupport.SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
|
||||
log.warn("Emitter executor did not terminate before the timeout period had elapsed");
|
||||
emitterExecutor.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
emitterExecutor.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit the specified {@link ProviderEvent}.
|
||||
*
|
||||
*
|
||||
* @param event The event type
|
||||
* @param details The details of the event
|
||||
*/
|
||||
public void emit(ProviderEvent event, ProviderEventDetails details) {
|
||||
if (this.onEmit != null) {
|
||||
this.onEmit.accept(this, 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a {@link ProviderEvent#PROVIDER_READY} event.
|
||||
* Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)}
|
||||
*
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a
|
||||
* {@link ProviderEvent#PROVIDER_CONFIGURATION_CHANGED}
|
||||
* event. Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)}
|
||||
*
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a {@link ProviderEvent#PROVIDER_STALE} event.
|
||||
* Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)}
|
||||
*
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a {@link ProviderEvent#PROVIDER_ERROR} event.
|
||||
* Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)}
|
||||
*
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
@FunctionalInterface
|
||||
interface EventProviderListener {
|
||||
void onEmit(ProviderEvent event, ProviderEventDetails details);
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
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;
|
||||
import java.util.function.Consumer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Util class for storing and running handlers.
|
||||
|
@ -20,90 +19,79 @@ import java.util.function.Consumer;
|
|||
@Slf4j
|
||||
class EventSupport {
|
||||
|
||||
public static final int SHUTDOWN_TIMEOUT_SECONDS = 3;
|
||||
|
||||
// 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 int SHUTDOWN_TIMEOUT_SECONDS = 3;
|
||||
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);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
private final ExecutorService taskExecutor = Executors.newCachedThreadPool();
|
||||
|
||||
/**
|
||||
* Run all the event handlers associated with this client name.
|
||||
* If the client name is null, handlers attached to unnamed clients will run.
|
||||
*
|
||||
* @param clientName the client name to run event handlers for, or null
|
||||
* Run all the event handlers associated with this domain.
|
||||
* If the domain is null, handlers attached to unnamed clients will run.
|
||||
*
|
||||
* @param domain the domain to run event handlers for, or null
|
||||
* @param event the event type
|
||||
* @param eventDetails the event details
|
||||
*/
|
||||
public void runClientHandlers(String clientName, ProviderEvent event, EventDetails eventDetails) {
|
||||
clientName = Optional.ofNullable(clientName)
|
||||
.orElse(defaultClientUuid);
|
||||
public void runClientHandlers(String domain, ProviderEvent event, EventDetails eventDetails) {
|
||||
domain = Optional.ofNullable(domain).orElse(DEFAULT_CLIENT_UUID);
|
||||
|
||||
// run handlers if they exist
|
||||
Optional.ofNullable(handlerStores.get(clientName))
|
||||
.filter(store -> Optional.of(store).isPresent())
|
||||
Optional.ofNullable(handlerStores.get(domain))
|
||||
.map(store -> store.handlerMap.get(event))
|
||||
.ifPresent(handlers -> handlers
|
||||
.forEach(handler -> runHandler(handler, eventDetails)));
|
||||
.ifPresent(handlers -> handlers.forEach(handler -> runHandler(handler, eventDetails)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all the API (global) event handlers.
|
||||
*
|
||||
*
|
||||
* @param event the event type
|
||||
* @param eventDetails the event details
|
||||
*/
|
||||
public void runGlobalHandlers(ProviderEvent event, EventDetails eventDetails) {
|
||||
globalHandlerStore.handlerMap.get(event)
|
||||
.forEach(handler -> {
|
||||
runHandler(handler, eventDetails);
|
||||
});
|
||||
globalHandlerStore.handlerMap.get(event).forEach(handler -> {
|
||||
runHandler(handler, eventDetails);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a handler for the specified client name, or all unnamed clients.
|
||||
*
|
||||
* @param clientName the client name to add handlers for, or else the unnamed
|
||||
* client
|
||||
* @param event the event type
|
||||
* @param handler the handler function to run
|
||||
* Add a handler for the specified domain, or all unnamed clients.
|
||||
*
|
||||
* @param domain the domain to add handlers for, or else unnamed
|
||||
* @param event the event type
|
||||
* @param handler the handler function to run
|
||||
*/
|
||||
public void addClientHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
final String name = Optional.ofNullable(clientName)
|
||||
.orElse(defaultClientUuid);
|
||||
public void addClientHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
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(() -> {
|
||||
HandlerStore newStore = new HandlerStore();
|
||||
this.handlerStores.put(name, newStore);
|
||||
return newStore;
|
||||
});
|
||||
HandlerStore store = Optional.ofNullable(this.handlerStores.get(name)).orElseGet(() -> {
|
||||
HandlerStore newStore = new HandlerStore();
|
||||
this.handlerStores.put(name, newStore);
|
||||
return newStore;
|
||||
});
|
||||
store.addHandler(event, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a client event handler for the specified event type.
|
||||
*
|
||||
* @param clientName the name of the client handler to remove, or null to remove
|
||||
* from unnamed clients
|
||||
* @param event the event type
|
||||
* @param handler the handler ref to be removed
|
||||
*
|
||||
* @param domain the domain of the client handler to remove, or null to remove
|
||||
* from unnamed clients
|
||||
* @param event the event type
|
||||
* @param handler the handler ref to be removed
|
||||
*/
|
||||
public void removeClientHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
clientName = Optional.ofNullable(clientName)
|
||||
.orElse(defaultClientUuid);
|
||||
this.handlerStores.get(clientName).removeHandler(event, handler);
|
||||
public void removeClientHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
domain = Optional.ofNullable(domain).orElse(DEFAULT_CLIENT_UUID);
|
||||
this.handlerStores.get(domain).removeHandler(event, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a global event handler of the specified event type.
|
||||
*
|
||||
*
|
||||
* @param event the event type
|
||||
* @param handler the handler to be added
|
||||
*/
|
||||
|
@ -113,7 +101,7 @@ class EventSupport {
|
|||
|
||||
/**
|
||||
* Remove a global event handler for the specified event type.
|
||||
*
|
||||
*
|
||||
* @param event the event type
|
||||
* @param handler the handler ref to be removed
|
||||
*/
|
||||
|
@ -122,17 +110,17 @@ class EventSupport {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all client names for which we have event handlers registered.
|
||||
*
|
||||
* @return set of client names
|
||||
* Get all domain names for which we have event handlers registered.
|
||||
*
|
||||
* @return set of domain names
|
||||
*/
|
||||
public Set<String> getAllClientNames() {
|
||||
public Set<String> getAllDomainNames() {
|
||||
return this.handlerStores.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the passed handler on the taskExecutor.
|
||||
*
|
||||
*
|
||||
* @param handler the handler to run
|
||||
* @param eventDetails the event details
|
||||
*/
|
||||
|
@ -168,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) {
|
||||
|
|
|
@ -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
|
||||
|
@ -60,13 +62,23 @@ public interface FeatureProvider {
|
|||
* If the provider needs to be initialized, it should return {@link ProviderState#NOT_READY}.
|
||||
* If the provider is in an error state, it should return {@link ProviderState#ERROR}.
|
||||
* If the provider is functioning normally, it should return {@link ProviderState#READY}.
|
||||
*
|
||||
*
|
||||
* <p><i>Providers which do not implement this method are assumed to be ready immediately.</i></p>
|
||||
*
|
||||
*
|
||||
* @return ProviderState
|
||||
* @deprecated The state is handled by the SDK internally. Query the state from the {@link Client} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default ProviderState getState() {
|
||||
return ProviderState.READY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feature provider implementations can opt in for to support Tracking by implementing this method.
|
||||
*
|
||||
* @param eventName The name of the tracking event
|
||||
* @param context Evaluation context used in flag evaluation (Optional)
|
||||
* @param details Data pertinent to a particular tracking event (Optional)
|
||||
*/
|
||||
default void track(String eventName, EvaluationContext context, TrackingEventDetails details) {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
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();
|
||||
private final AtomicReference<ProviderState> state = new AtomicReference<>(ProviderState.NOT_READY);
|
||||
|
||||
public FeatureProviderStateManager(FeatureProvider delegate) {
|
||||
this.delegate = delegate;
|
||||
if (delegate instanceof EventProvider) {
|
||||
((EventProvider) delegate).setEventProviderListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize(EvaluationContext evaluationContext) throws Exception {
|
||||
if (isInitialized.getAndSet(true)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
delegate.initialize(evaluationContext);
|
||||
setState(ProviderState.READY);
|
||||
} catch (OpenFeatureError openFeatureError) {
|
||||
if (ErrorCode.PROVIDER_FATAL.equals(openFeatureError.getErrorCode())) {
|
||||
setState(ProviderState.FATAL);
|
||||
} else {
|
||||
setState(ProviderState.ERROR);
|
||||
}
|
||||
isInitialized.set(false);
|
||||
throw openFeatureError;
|
||||
} catch (Exception e) {
|
||||
setState(ProviderState.ERROR);
|
||||
isInitialized.set(false);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
delegate.shutdown();
|
||||
setState(ProviderState.NOT_READY);
|
||||
isInitialized.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEmit(ProviderEvent event, ProviderEventDetails details) {
|
||||
if (ProviderEvent.PROVIDER_ERROR.equals(event)) {
|
||||
if (details != null && details.getErrorCode() == ErrorCode.PROVIDER_FATAL) {
|
||||
setState(ProviderState.FATAL);
|
||||
} else {
|
||||
setState(ProviderState.ERROR);
|
||||
}
|
||||
} else if (ProviderEvent.PROVIDER_STALE.equals(event)) {
|
||||
setState(ProviderState.STALE);
|
||||
} else if (ProviderEvent.PROVIDER_READY.equals(event)) {
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean hasSameProvider(FeatureProvider featureProvider) {
|
||||
return this.delegate.equals(featureProvider);
|
||||
}
|
||||
}
|
|
@ -15,8 +15,8 @@ public interface Features {
|
|||
|
||||
FlagEvaluationDetails<Boolean> getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx);
|
||||
|
||||
FlagEvaluationDetails<Boolean> getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options);
|
||||
FlagEvaluationDetails<Boolean> getBooleanDetails(
|
||||
String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
|
||||
|
||||
String getStringValue(String key, String defaultValue);
|
||||
|
||||
|
@ -28,8 +28,8 @@ public interface Features {
|
|||
|
||||
FlagEvaluationDetails<String> getStringDetails(String key, String defaultValue, EvaluationContext ctx);
|
||||
|
||||
FlagEvaluationDetails<String> getStringDetails(String key, String defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options);
|
||||
FlagEvaluationDetails<String> getStringDetails(
|
||||
String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
|
||||
|
||||
Integer getIntegerValue(String key, Integer defaultValue);
|
||||
|
||||
|
@ -41,8 +41,8 @@ public interface Features {
|
|||
|
||||
FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx);
|
||||
|
||||
FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options);
|
||||
FlagEvaluationDetails<Integer> getIntegerDetails(
|
||||
String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
|
||||
|
||||
Double getDoubleValue(String key, Double defaultValue);
|
||||
|
||||
|
@ -54,22 +54,19 @@ public interface Features {
|
|||
|
||||
FlagEvaluationDetails<Double> getDoubleDetails(String key, Double defaultValue, EvaluationContext ctx);
|
||||
|
||||
FlagEvaluationDetails<Double> getDoubleDetails(String key, Double defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options);
|
||||
FlagEvaluationDetails<Double> getDoubleDetails(
|
||||
String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
|
||||
|
||||
Value getObjectValue(String key, Value defaultValue);
|
||||
|
||||
Value getObjectValue(String key, Value defaultValue, EvaluationContext ctx);
|
||||
|
||||
Value getObjectValue(String key, Value defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options);
|
||||
Value getObjectValue(String key, Value defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
|
||||
|
||||
FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue);
|
||||
|
||||
FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue,
|
||||
EvaluationContext ctx);
|
||||
FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue, EvaluationContext ctx);
|
||||
|
||||
FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue,
|
||||
EvaluationContext ctx,
|
||||
FlagEvaluationOptions options);
|
||||
FlagEvaluationDetails<Value> getObjectDetails(
|
||||
String key, Value defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
@ -25,6 +24,7 @@ public class FlagEvaluationDetails<T> implements BaseEvaluation<T> {
|
|||
private String reason;
|
||||
private ErrorCode errorCode;
|
||||
private String errorMessage;
|
||||
|
||||
@Builder.Default
|
||||
private ImmutableMetadata flagMetadata = ImmutableMetadata.builder().build();
|
||||
|
||||
|
@ -44,8 +44,8 @@ public class FlagEvaluationDetails<T> implements BaseEvaluation<T> {
|
|||
.reason(providerEval.getReason())
|
||||
.errorMessage(providerEval.getErrorMessage())
|
||||
.errorCode(providerEval.getErrorCode())
|
||||
.flagMetadata(
|
||||
Optional.ofNullable(providerEval.getFlagMetadata()).orElse(ImmutableMetadata.builder().build()))
|
||||
.flagMetadata(Optional.ofNullable(providerEval.getFlagMetadata())
|
||||
.orElse(ImmutableMetadata.builder().build()))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package dev.openfeature.sdk;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Singular;
|
||||
|
||||
|
@ -13,6 +12,7 @@ import lombok.Singular;
|
|||
public class FlagEvaluationOptions {
|
||||
@Singular
|
||||
List<Hook> hooks;
|
||||
|
||||
@Builder.Default
|
||||
Map<String, Object> hookHints = new HashMap<>();
|
||||
}
|
||||
|
|
|
@ -2,5 +2,9 @@ package dev.openfeature.sdk;
|
|||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
public enum FlagValueType {
|
||||
STRING, INTEGER, DOUBLE, OBJECT, BOOLEAN;
|
||||
STRING,
|
||||
INTEGER,
|
||||
DOUBLE,
|
||||
OBJECT,
|
||||
BOOLEAN;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public interface Hook<T> {
|
|||
* @param ctx Information about the particular flag evaluation
|
||||
* @param hints An immutable mapping of data for users to communicate to the hooks.
|
||||
* @return An optional {@link EvaluationContext}. If returned, it will be merged with the EvaluationContext
|
||||
* instances from other hooks, the client and API.
|
||||
* instances from other hooks, the client and API.
|
||||
*/
|
||||
default Optional<EvaluationContext> before(HookContext<T> ctx, Map<String, Object> hints) {
|
||||
return Optional.empty();
|
||||
|
@ -29,8 +29,7 @@ public interface Hook<T> {
|
|||
* @param details Information about how the flag was resolved, including any resolved values.
|
||||
* @param hints An immutable mapping of data for users to communicate to the hooks.
|
||||
*/
|
||||
default void after(HookContext<T> ctx, FlagEvaluationDetails<T> details, Map<String, Object> hints) {
|
||||
}
|
||||
default void after(HookContext<T> ctx, FlagEvaluationDetails<T> details, Map<String, Object> hints) {}
|
||||
|
||||
/**
|
||||
* Run when evaluation encounters an error. This will always run. Errors thrown will be swallowed.
|
||||
|
@ -39,8 +38,7 @@ public interface Hook<T> {
|
|||
* @param error The exception that was thrown.
|
||||
* @param hints An immutable mapping of data for users to communicate to the hooks.
|
||||
*/
|
||||
default void error(HookContext<T> ctx, Exception error, Map<String, Object> hints) {
|
||||
}
|
||||
default void error(HookContext<T> ctx, Exception error, Map<String, Object> hints) {}
|
||||
|
||||
/**
|
||||
* Run after flag evaluation, including any error processing. This will always run. Errors will be swallowed.
|
||||
|
@ -48,8 +46,7 @@ public interface Hook<T> {
|
|||
* @param ctx Information about the particular flag evaluation
|
||||
* @param hints An immutable mapping of data for users to communicate to the hooks.
|
||||
*/
|
||||
default void finallyAfter(HookContext<T> ctx, Map<String, Object> hints) {
|
||||
}
|
||||
default void finallyAfter(HookContext<T> ctx, FlagEvaluationDetails<T> details, Map<String, Object> hints) {}
|
||||
|
||||
default boolean supportsFlagValueType(FlagValueType flagValueType) {
|
||||
return true;
|
||||
|
|
|
@ -10,28 +10,40 @@ import lombok.With;
|
|||
*
|
||||
* @param <T> the type for the flag being evaluated
|
||||
*/
|
||||
@Value @Builder @With
|
||||
@Value
|
||||
@Builder
|
||||
@With
|
||||
public class HookContext<T> {
|
||||
@NonNull String flagKey;
|
||||
|
||||
@NonNull FlagValueType type;
|
||||
|
||||
@NonNull T defaultValue;
|
||||
|
||||
@NonNull EvaluationContext ctx;
|
||||
Metadata clientMetadata;
|
||||
|
||||
ClientMetadata clientMetadata;
|
||||
Metadata providerMetadata;
|
||||
|
||||
/**
|
||||
* Builds a {@link HookContext} instances from request data.
|
||||
* @param key feature flag key
|
||||
* @param type flag value type
|
||||
* @param clientMetadata info on which client is calling
|
||||
*
|
||||
* @param key feature flag key
|
||||
* @param type flag value type
|
||||
* @param clientMetadata info on which client is calling
|
||||
* @param providerMetadata info on the provider
|
||||
* @param ctx Evaluation Context for the request
|
||||
* @param defaultValue Fallback value
|
||||
* @param <T> type that the flag is evaluating against
|
||||
* @param ctx Evaluation Context for the request
|
||||
* @param defaultValue Fallback value
|
||||
* @param <T> type that the flag is evaluating against
|
||||
* @return resulting context for hook
|
||||
*/
|
||||
public static <T> HookContext<T> from(String key, FlagValueType type, Metadata clientMetadata,
|
||||
Metadata providerMetadata, EvaluationContext ctx, T defaultValue) {
|
||||
public static <T> HookContext<T> from(
|
||||
String key,
|
||||
FlagValueType type,
|
||||
ClientMetadata clientMetadata,
|
||||
Metadata providerMetadata,
|
||||
EvaluationContext ctx,
|
||||
T defaultValue) {
|
||||
return HookContext.<T>builder()
|
||||
.flagKey(key)
|
||||
.type(type)
|
||||
|
|
|
@ -1,93 +1,101 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
class HookSupport {
|
||||
|
||||
public void errorHooks(FlagValueType flagValueType, HookContext hookCtx, Exception e, List<Hook> hooks,
|
||||
public EvaluationContext beforeHooks(
|
||||
FlagValueType flagValueType, HookContext hookCtx, List<Hook> hooks, Map<String, Object> hints) {
|
||||
return callBeforeHooks(flagValueType, hookCtx, hooks, hints);
|
||||
}
|
||||
|
||||
public void afterHooks(
|
||||
FlagValueType flagValueType,
|
||||
HookContext hookContext,
|
||||
FlagEvaluationDetails details,
|
||||
List<Hook> hooks,
|
||||
Map<String, Object> hints) {
|
||||
executeHooksUnchecked(flagValueType, hooks, hook -> hook.after(hookContext, details, hints));
|
||||
}
|
||||
|
||||
public void afterAllHooks(
|
||||
FlagValueType flagValueType,
|
||||
HookContext hookCtx,
|
||||
FlagEvaluationDetails details,
|
||||
List<Hook> hooks,
|
||||
Map<String, Object> hints) {
|
||||
executeHooks(flagValueType, hooks, "finally", hook -> hook.finallyAfter(hookCtx, details, hints));
|
||||
}
|
||||
|
||||
public void errorHooks(
|
||||
FlagValueType flagValueType,
|
||||
HookContext hookCtx,
|
||||
Exception e,
|
||||
List<Hook> hooks,
|
||||
Map<String, Object> hints) {
|
||||
executeHooks(flagValueType, hooks, "error", hook -> hook.error(hookCtx, e, hints));
|
||||
}
|
||||
|
||||
public void afterAllHooks(FlagValueType flagValueType, HookContext hookCtx, List<Hook> hooks,
|
||||
Map<String, Object> hints) {
|
||||
executeHooks(flagValueType, hooks, "finally", hook -> hook.finallyAfter(hookCtx, hints));
|
||||
}
|
||||
|
||||
public void afterHooks(FlagValueType flagValueType, HookContext hookContext, FlagEvaluationDetails details,
|
||||
List<Hook> hooks, Map<String, Object> hints) {
|
||||
executeHooksUnchecked(flagValueType, hooks, hook -> hook.after(hookContext, details, hints));
|
||||
}
|
||||
|
||||
private <T> void executeHooks(
|
||||
FlagValueType flagValueType, List<Hook> hooks,
|
||||
String hookMethod,
|
||||
Consumer<Hook<T>> hookCode) {
|
||||
FlagValueType flagValueType, List<Hook> hooks, String hookMethod, Consumer<Hook<T>> hookCode) {
|
||||
if (hooks != null) {
|
||||
hooks
|
||||
.stream()
|
||||
.filter(hook -> hook.supportsFlagValueType(flagValueType))
|
||||
.forEach(hook -> executeChecked(hook, hookCode, hookMethod));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void executeHooksUnchecked(
|
||||
FlagValueType flagValueType, List<Hook> hooks,
|
||||
Consumer<Hook<T>> hookCode) {
|
||||
if (hooks != null) {
|
||||
hooks
|
||||
.stream()
|
||||
.filter(hook -> hook.supportsFlagValueType(flagValueType))
|
||||
.forEach(hookCode::accept);
|
||||
for (Hook hook : hooks) {
|
||||
if (hook.supportsFlagValueType(flagValueType)) {
|
||||
executeChecked(hook, hookCode, hookMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// before, error, and finally hooks shouldn't throw
|
||||
private <T> void executeChecked(Hook<T> hook, Consumer<Hook<T>> hookCode, String hookMethod) {
|
||||
try {
|
||||
hookCode.accept(hook);
|
||||
} catch (Exception exception) {
|
||||
log.error("Exception when running {} hooks {}", hookMethod, hook.getClass(), exception);
|
||||
log.error(
|
||||
"Unhandled exception when running {} hook {} (only 'after' hooks should throw)",
|
||||
hookMethod,
|
||||
hook.getClass(),
|
||||
exception);
|
||||
}
|
||||
}
|
||||
|
||||
public EvaluationContext beforeHooks(FlagValueType flagValueType, HookContext hookCtx, List<Hook> hooks,
|
||||
Map<String, Object> hints) {
|
||||
Stream<EvaluationContext> result = callBeforeHooks(flagValueType, hookCtx, hooks, hints);
|
||||
return hookCtx.getCtx().merge(
|
||||
result.reduce(hookCtx.getCtx(), (EvaluationContext accumulated, EvaluationContext current) -> {
|
||||
return accumulated.merge(current);
|
||||
}));
|
||||
// after hooks can throw in order to do validation
|
||||
private <T> void executeHooksUnchecked(FlagValueType flagValueType, List<Hook> hooks, Consumer<Hook<T>> hookCode) {
|
||||
if (hooks != null) {
|
||||
for (Hook hook : hooks) {
|
||||
if (hook.supportsFlagValueType(flagValueType)) {
|
||||
hookCode.accept(hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Stream<EvaluationContext> callBeforeHooks(FlagValueType flagValueType, HookContext hookCtx,
|
||||
List<Hook> hooks, Map<String, Object> hints) {
|
||||
private EvaluationContext callBeforeHooks(
|
||||
FlagValueType flagValueType, HookContext hookCtx, List<Hook> hooks, Map<String, Object> hints) {
|
||||
// These traverse backwards from normal.
|
||||
List<Hook> reversedHooks = IntStream
|
||||
.range(0, hooks.size())
|
||||
.map(i -> hooks.size() - 1 - i)
|
||||
.mapToObj(hooks::get)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return reversedHooks
|
||||
.stream()
|
||||
.filter(hook -> hook.supportsFlagValueType(flagValueType))
|
||||
.map(hook -> hook.before(hookCtx, hints))
|
||||
.filter(Objects::nonNull)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.map(EvaluationContext.class::cast);
|
||||
List<Hook> reversedHooks = new ArrayList<>(hooks);
|
||||
Collections.reverse(reversedHooks);
|
||||
EvaluationContext context = hookCtx.getCtx();
|
||||
for (Hook hook : reversedHooks) {
|
||||
if (hook.supportsFlagValueType(flagValueType)) {
|
||||
Optional<EvaluationContext> optional =
|
||||
Optional.ofNullable(hook.before(hookCtx, hints)).orElse(Optional.empty());
|
||||
if (optional.isPresent()) {
|
||||
context = context.merge(optional.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,31 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
/**
|
||||
* The EvaluationContext is a container for arbitrary contextual data
|
||||
* that can be used as a basis for dynamic evaluation.
|
||||
* The ImmutableContext is an EvaluationContext implementation which is threadsafe, and whose attributes can
|
||||
* The ImmutableContext is an EvaluationContext implementation which is
|
||||
* threadsafe, and whose attributes can
|
||||
* not be modified after instantiation.
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||
public final class ImmutableContext implements EvaluationContext {
|
||||
|
||||
@Delegate
|
||||
private final Structure structure;
|
||||
@Delegate(excludes = DelegateExclusions.class)
|
||||
private final ImmutableStructure structure;
|
||||
|
||||
/**
|
||||
* Create an immutable context with an empty targeting_key and attributes provided.
|
||||
* Create an immutable context with an empty targeting_key and attributes
|
||||
* provided.
|
||||
*/
|
||||
public ImmutableContext() {
|
||||
this(new HashMap<>());
|
||||
|
@ -41,7 +46,7 @@ public final class ImmutableContext implements EvaluationContext {
|
|||
* @param attributes evaluation context attributes
|
||||
*/
|
||||
public ImmutableContext(Map<String, Value> attributes) {
|
||||
this("", attributes);
|
||||
this(null, attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,9 +57,7 @@ public final class ImmutableContext implements EvaluationContext {
|
|||
*/
|
||||
public ImmutableContext(String targetingKey, Map<String, Value> attributes) {
|
||||
if (targetingKey != null && !targetingKey.trim().isEmpty()) {
|
||||
final Map<String, Value> actualAttribs = new HashMap<>(attributes);
|
||||
actualAttribs.put(TARGETING_KEY, new Value(targetingKey));
|
||||
this.structure = new ImmutableStructure(actualAttribs);
|
||||
this.structure = new ImmutableStructure(targetingKey, attributes);
|
||||
} else {
|
||||
this.structure = new ImmutableStructure(attributes);
|
||||
}
|
||||
|
@ -70,18 +73,34 @@ public final class ImmutableContext implements EvaluationContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Merges this EvaluationContext object with the passed EvaluationContext, overriding in case of conflict.
|
||||
* Merges this EvaluationContext object with the passed EvaluationContext,
|
||||
* overriding in case of conflict.
|
||||
*
|
||||
* @param overridingContext overriding context
|
||||
* @return resulting merged context
|
||||
* @return new, resulting merged context
|
||||
*/
|
||||
@Override
|
||||
public EvaluationContext merge(EvaluationContext overridingContext) {
|
||||
if (overridingContext == null) {
|
||||
return new ImmutableContext(this.asMap());
|
||||
if (overridingContext == null || overridingContext.isEmpty()) {
|
||||
return new ImmutableContext(this.asUnmodifiableMap());
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
return new ImmutableContext(overridingContext.asUnmodifiableMap());
|
||||
}
|
||||
|
||||
return new ImmutableContext(
|
||||
this.merge(ImmutableStructure::new, this.asMap(), overridingContext.asMap()));
|
||||
Map<String, Value> attributes = this.asMap();
|
||||
EvaluationContext.mergeMaps(ImmutableStructure::new, attributes, overridingContext.asUnmodifiableMap());
|
||||
return new ImmutableContext(attributes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static class DelegateExclusions {
|
||||
@ExcludeFromGeneratedCoverageReport
|
||||
public <T extends Structure> Map<String, Value> merge(
|
||||
Function<Map<String, Value>, Structure> newStructure,
|
||||
Map<String, Value> base,
|
||||
Map<String, Value> overriding) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Immutable Flag Metadata representation. Implementation is backed by a {@link Map} and immutability is provided
|
||||
|
@ -98,6 +97,13 @@ public class ImmutableMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return metadata.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isNotEmpty() {
|
||||
return !metadata.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a builder for {@link ImmutableMetadata}.
|
||||
|
@ -188,6 +194,5 @@ public class ImmutableMetadata {
|
|||
public ImmutableMetadata build() {
|
||||
return new ImmutableMetadata(this.metadata);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ package dev.openfeature.sdk;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
|
@ -18,8 +18,8 @@ import lombok.ToString;
|
|||
* not be modified after instantiation. All references are clones.
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" })
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
|
||||
public final class ImmutableStructure extends AbstractStructure {
|
||||
|
||||
/**
|
||||
|
@ -35,14 +35,11 @@ public final class ImmutableStructure extends AbstractStructure {
|
|||
* @param attributes attributes.
|
||||
*/
|
||||
public ImmutableStructure(Map<String, Value> attributes) {
|
||||
super(new HashMap<>(attributes.entrySet()
|
||||
.stream()
|
||||
.collect(HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(),
|
||||
Optional.ofNullable(entry.getValue())
|
||||
.map(Value::clone)
|
||||
.orElse(null)),
|
||||
HashMap::putAll)));
|
||||
super(copyAttributes(attributes, null));
|
||||
}
|
||||
|
||||
ImmutableStructure(String targetingKey, Map<String, Value> attributes) {
|
||||
super(copyAttributes(attributes, targetingKey));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,7 +50,7 @@ public final class ImmutableStructure extends AbstractStructure {
|
|||
// getters
|
||||
@Override
|
||||
public Value getValue(String key) {
|
||||
Value value = this.attributes.get(key);
|
||||
Value value = attributes.get(key);
|
||||
return value != null ? value.clone() : null;
|
||||
}
|
||||
|
||||
|
@ -64,14 +61,27 @@ public final class ImmutableStructure extends AbstractStructure {
|
|||
*/
|
||||
@Override
|
||||
public Map<String, Value> asMap() {
|
||||
return attributes
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(),
|
||||
Optional.ofNullable(entry.getValue())
|
||||
.map(Value::clone)
|
||||
.orElse(null)),
|
||||
HashMap::putAll);
|
||||
return copyAttributes(attributes);
|
||||
}
|
||||
|
||||
private static Map<String, Value> copyAttributes(Map<String, Value> in) {
|
||||
return copyAttributes(in, null);
|
||||
}
|
||||
|
||||
private static Map<String, Value> copyAttributes(Map<String, Value> in, String targetingKey) {
|
||||
Map<String, Value> copy = new HashMap<>();
|
||||
if (in != null) {
|
||||
for (Entry<String, Value> entry : in.entrySet()) {
|
||||
copy.put(
|
||||
entry.getKey(),
|
||||
Optional.ofNullable(entry.getValue())
|
||||
.map((Value val) -> val.clone())
|
||||
.orElse(null));
|
||||
}
|
||||
}
|
||||
if (targetingKey != null) {
|
||||
copy.put(EvaluationContext.TARGETING_KEY, new Value(targetingKey));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
/**
|
||||
* ImmutableTrackingEventDetails represents data pertinent to a particular tracking event.
|
||||
*/
|
||||
public class ImmutableTrackingEventDetails implements TrackingEventDetails {
|
||||
|
||||
@Delegate(excludes = DelegateExclusions.class)
|
||||
private final ImmutableStructure structure;
|
||||
|
||||
private final Number value;
|
||||
|
||||
public ImmutableTrackingEventDetails() {
|
||||
this.value = null;
|
||||
this.structure = new ImmutableStructure();
|
||||
}
|
||||
|
||||
public ImmutableTrackingEventDetails(final Number value) {
|
||||
this.value = value;
|
||||
this.structure = new ImmutableStructure();
|
||||
}
|
||||
|
||||
public ImmutableTrackingEventDetails(final Number value, final Map<String, Value> attributes) {
|
||||
this.value = value;
|
||||
this.structure = new ImmutableStructure(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the optional tracking value.
|
||||
*/
|
||||
public Optional<Number> getValue() {
|
||||
return Optional.ofNullable(value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static class DelegateExclusions {
|
||||
@ExcludeFromGeneratedCoverageReport
|
||||
public <T extends Structure> Map<String, Value> merge(
|
||||
Function<Map<String, Value>, Structure> newStructure,
|
||||
Map<String, Value> base,
|
||||
Map<String, Value> overriding) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic
|
||||
* to the lifecycle of flag evaluation.
|
||||
*
|
||||
* @see Hook
|
||||
*/
|
||||
public interface IntegerHook extends Hook<Integer> {
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
/**
|
||||
* The EvaluationContext is a container for arbitrary contextual data
|
||||
|
@ -20,7 +21,8 @@ import java.util.Map;
|
|||
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||
public class MutableContext implements EvaluationContext {
|
||||
|
||||
@Delegate(excludes = HideDelegateAddMethods.class) private final MutableStructure structure;
|
||||
@Delegate(excludes = DelegateExclusions.class)
|
||||
private final MutableStructure structure;
|
||||
|
||||
public MutableContext() {
|
||||
this(new HashMap<>());
|
||||
|
@ -31,7 +33,7 @@ public class MutableContext implements EvaluationContext {
|
|||
}
|
||||
|
||||
public MutableContext(Map<String, Value> attributes) {
|
||||
this("", attributes);
|
||||
this(null, new HashMap<>(attributes));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,7 +44,7 @@ public class MutableContext implements EvaluationContext {
|
|||
* @param attributes evaluation context attributes
|
||||
*/
|
||||
public MutableContext(String targetingKey, Map<String, Value> attributes) {
|
||||
this.structure = new MutableStructure(attributes);
|
||||
this.structure = new MutableStructure(new HashMap<>(attributes));
|
||||
if (targetingKey != null && !targetingKey.trim().isEmpty()) {
|
||||
this.structure.attributes.put(TARGETING_KEY, new Value(targetingKey));
|
||||
}
|
||||
|
@ -94,7 +96,6 @@ public class MutableContext implements EvaluationContext {
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve targetingKey from the context.
|
||||
*/
|
||||
|
@ -112,23 +113,37 @@ public class MutableContext implements EvaluationContext {
|
|||
*/
|
||||
@Override
|
||||
public EvaluationContext merge(EvaluationContext overridingContext) {
|
||||
if (overridingContext == null) {
|
||||
return new MutableContext(this.asMap());
|
||||
if (overridingContext == null || overridingContext.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
return overridingContext;
|
||||
}
|
||||
|
||||
Map<String, Value> merged = this.merge(
|
||||
MutableStructure::new, this.asMap(), overridingContext.asMap());
|
||||
return new MutableContext(merged);
|
||||
Map<String, Value> attributes = this.asMap();
|
||||
EvaluationContext.mergeMaps(MutableStructure::new, attributes, overridingContext.asUnmodifiableMap());
|
||||
return new MutableContext(attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden class to tell Lombok not to copy these methods over via delegation.
|
||||
*/
|
||||
private static class HideDelegateAddMethods {
|
||||
@SuppressWarnings("all")
|
||||
private static class DelegateExclusions {
|
||||
|
||||
@ExcludeFromGeneratedCoverageReport
|
||||
public <T extends Structure> Map<String, Value> merge(
|
||||
Function<Map<String, Value>, Structure> newStructure,
|
||||
Map<String, Value> base,
|
||||
Map<String, Value> overriding) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MutableStructure add(String ignoredKey, Boolean ignoredValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public MutableStructure add(String ignoredKey, Double ignoredValue) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -5,19 +5,18 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* {@link MutableStructure} represents a potentially nested object type which is used to represent
|
||||
* {@link MutableStructure} represents a potentially nested object type which is used to represent
|
||||
* structured data.
|
||||
* The MutableStructure is a Structure implementation which is not threadsafe, and whose attributes can
|
||||
* The MutableStructure is a Structure implementation which is not threadsafe, and whose attributes can
|
||||
* be modified after instantiation.
|
||||
*/
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MutableStructure extends AbstractStructure {
|
||||
|
||||
public MutableStructure() {
|
||||
|
@ -30,13 +29,13 @@ public class MutableStructure extends AbstractStructure {
|
|||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return this.attributes.keySet();
|
||||
return attributes.keySet();
|
||||
}
|
||||
|
||||
// getters
|
||||
@Override
|
||||
public Value getValue(String key) {
|
||||
return this.attributes.get(key);
|
||||
return attributes.get(key);
|
||||
}
|
||||
|
||||
// adders
|
||||
|
@ -87,6 +86,6 @@ public class MutableStructure extends AbstractStructure {
|
|||
*/
|
||||
@Override
|
||||
public Map<String, Value> asMap() {
|
||||
return new HashMap<>(this.attributes);
|
||||
return new HashMap<>(attributes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Delegate;
|
||||
|
||||
/**
|
||||
* MutableTrackingEventDetails represents data pertinent to a particular tracking event.
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
@ToString
|
||||
public class MutableTrackingEventDetails implements TrackingEventDetails {
|
||||
|
||||
private final Number value;
|
||||
|
||||
@Delegate(excludes = MutableTrackingEventDetails.DelegateExclusions.class)
|
||||
private final MutableStructure structure;
|
||||
|
||||
public MutableTrackingEventDetails() {
|
||||
this.value = null;
|
||||
this.structure = new MutableStructure();
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails(final Number value) {
|
||||
this.value = value;
|
||||
this.structure = new MutableStructure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the optional tracking value.
|
||||
*/
|
||||
public Optional<Number> getValue() {
|
||||
return Optional.ofNullable(value);
|
||||
}
|
||||
|
||||
// override @Delegate methods so that we can use "add" methods and still return MutableTrackingEventDetails,
|
||||
// not Structure
|
||||
public MutableTrackingEventDetails add(String key, Boolean value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, String value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, Integer value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, Double value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, Instant value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, Structure value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, List<Value> value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MutableTrackingEventDetails add(String key, Value value) {
|
||||
this.structure.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private static class DelegateExclusions {
|
||||
@ExcludeFromGeneratedCoverageReport
|
||||
public <T extends Structure> Map<String, Value> merge(
|
||||
Function<Map<String, Value>, Structure> newStructure,
|
||||
Map<String, Value> base,
|
||||
Map<String, Value> overriding) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import lombok.Getter;
|
|||
*/
|
||||
public class NoOpProvider implements FeatureProvider {
|
||||
public static final String PASSED_IN_DEFAULT = "Passed in default";
|
||||
|
||||
@Getter
|
||||
private final String name = "No-op Provider";
|
||||
|
||||
|
@ -58,8 +59,8 @@ public class NoOpProvider implements FeatureProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue,
|
||||
EvaluationContext invocationContext) {
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(
|
||||
String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
return ProviderEvaluation.<Value>builder()
|
||||
.value(defaultValue)
|
||||
.variant(PASSED_IN_DEFAULT)
|
||||
|
|
|
@ -7,6 +7,7 @@ public class NoOpTransactionContextPropagator implements TransactionContextPropa
|
|||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return empty immutable context
|
||||
*/
|
||||
@Override
|
||||
|
@ -18,7 +19,5 @@ public class NoOpTransactionContextPropagator implements TransactionContextPropa
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void setTransactionContext(EvaluationContext evaluationContext) {
|
||||
|
||||
}
|
||||
public void setTransactionContext(EvaluationContext evaluationContext) {}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -18,18 +20,19 @@ import lombok.extern.slf4j.Slf4j;
|
|||
* Configuration here will be shared across all {@link Client}s.
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings("PMD.UnusedLocalVariable")
|
||||
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<>();
|
||||
providerRepository = new ProviderRepository();
|
||||
apiHooks = new ConcurrentLinkedQueue<>();
|
||||
providerRepository = new ProviderRepository(this);
|
||||
eventSupport = new EventSupport();
|
||||
transactionContextPropagator = new NoOpTransactionContextPropagator();
|
||||
}
|
||||
|
@ -47,61 +50,92 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
|
|||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata about the default provider.
|
||||
*
|
||||
* @return the provider metadata
|
||||
*/
|
||||
public Metadata getProviderMetadata() {
|
||||
return getProvider().getMetadata();
|
||||
}
|
||||
|
||||
public Metadata getProviderMetadata(String clientName) {
|
||||
return getProvider(clientName).getMetadata();
|
||||
/**
|
||||
* Get metadata about a registered provider using the client name.
|
||||
* An unbound or empty client name will return metadata from the default provider.
|
||||
*
|
||||
* @param domain an identifier which logically binds clients with providers
|
||||
* @return the provider metadata
|
||||
*/
|
||||
public Metadata getProviderMetadata(String domain) {
|
||||
return getProvider(domain).getMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* A factory function for creating new, OpenFeature client.
|
||||
* Clients can contain their own state (e.g. logger, hook, context).
|
||||
* Multiple clients can be used to segment feature flag configuration.
|
||||
* All un-named or unbound clients use the default provider.
|
||||
*
|
||||
* @return a new client instance
|
||||
*/
|
||||
public Client getClient() {
|
||||
return getClient(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* A factory function for creating new domainless OpenFeature client.
|
||||
* Clients can contain their own state (e.g. logger, hook, context).
|
||||
* Multiple clients can be used to segment feature flag configuration.
|
||||
* If there is already a provider bound to this domain, this provider will be used.
|
||||
* Otherwise, the default provider is used until a provider is assigned to that domain.
|
||||
*
|
||||
* @param domain an identifier which logically binds clients with providers
|
||||
* @return a new client instance
|
||||
*/
|
||||
public Client getClient(String name) {
|
||||
return getClient(name, null);
|
||||
public Client getClient(String domain) {
|
||||
return getClient(domain, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* A factory function for creating new domainless OpenFeature client.
|
||||
* Clients can contain their own state (e.g. logger, hook, context).
|
||||
* Multiple clients can be used to segment feature flag configuration.
|
||||
* If there is already a provider bound to this domain, this provider will be used.
|
||||
* Otherwise, the default provider is used until a provider is assigned to that domain.
|
||||
*
|
||||
* @param domain a identifier which logically binds clients with providers
|
||||
* @param version a version identifier
|
||||
* @return a new client instance
|
||||
*/
|
||||
public Client getClient(String name, String version) {
|
||||
return new OpenFeatureClient(this,
|
||||
name,
|
||||
version);
|
||||
public Client getClient(String domain, String version) {
|
||||
return new OpenFeatureClient(this, domain, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Sets the global evaluation context, which will be used for all evaluations.
|
||||
*
|
||||
* @param evaluationContext the context
|
||||
* @return api instance
|
||||
*/
|
||||
public OpenFeatureAPI setEvaluationContext(EvaluationContext evaluationContext) {
|
||||
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
|
||||
this.evaluationContext = evaluationContext;
|
||||
}
|
||||
this.evaluationContext.set(evaluationContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Gets the global evaluation context, which will be used for all evaluations.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
@ -115,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;
|
||||
}
|
||||
}
|
||||
|
@ -141,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,
|
||||
|
@ -153,14 +187,15 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a provider for a named client.
|
||||
* Add a provider for a domain.
|
||||
*
|
||||
* @param clientName The name of the client.
|
||||
* @param provider The provider to set.
|
||||
* @param domain The domain to bind the provider to.
|
||||
* @param provider The provider to set.
|
||||
*/
|
||||
public void setProvider(String clientName, FeatureProvider provider) {
|
||||
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
|
||||
providerRepository.setProvider(clientName,
|
||||
public void setProvider(String domain, FeatureProvider provider) {
|
||||
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
|
||||
providerRepository.setProvider(
|
||||
domain,
|
||||
provider,
|
||||
this::attachEventProvider,
|
||||
this::emitReady,
|
||||
|
@ -171,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,
|
||||
|
@ -186,14 +227,19 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a provider for a named client and wait for initialization to finish.
|
||||
* Add a provider for a domain and wait for initialization to finish.
|
||||
*
|
||||
* @param clientName The name of the client.
|
||||
* @param provider The provider to set.
|
||||
* <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 clientName, FeatureProvider provider) throws OpenFeatureError {
|
||||
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
|
||||
providerRepository.setProvider(clientName,
|
||||
public void setProviderAndWait(String domain, FeatureProvider provider) throws OpenFeatureError {
|
||||
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
|
||||
providerRepository.setProvider(
|
||||
domain,
|
||||
provider,
|
||||
this::attachEventProvider,
|
||||
this::emitReady,
|
||||
|
@ -205,14 +251,15 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitReady(FeatureProvider provider) {
|
||||
runHandlersForProvider(provider, ProviderEvent.PROVIDER_READY, ProviderEventDetails.builder().build());
|
||||
runHandlersForProvider(
|
||||
provider,
|
||||
ProviderEvent.PROVIDER_READY,
|
||||
ProviderEventDetails.builder().build());
|
||||
}
|
||||
|
||||
private void detachEventProvider(FeatureProvider provider) {
|
||||
|
@ -222,7 +269,9 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
|
|||
}
|
||||
|
||||
private void emitError(FeatureProvider provider, OpenFeatureError exception) {
|
||||
runHandlersForProvider(provider, ProviderEvent.PROVIDER_ERROR,
|
||||
runHandlersForProvider(
|
||||
provider,
|
||||
ProviderEvent.PROVIDER_ERROR,
|
||||
ProviderEventDetails.builder().message(exception.getMessage()).build());
|
||||
}
|
||||
|
||||
|
@ -239,40 +288,48 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Fetch a provider for a named client. If not found, return the default.
|
||||
* Fetch a provider for a domain. If not found, return the default.
|
||||
*
|
||||
* @param name The client name to look for.
|
||||
* @param domain The domain to look for.
|
||||
* @return A named {@link FeatureProvider}
|
||||
*/
|
||||
public FeatureProvider getProvider(String name) {
|
||||
return providerRepository.getProvider(name);
|
||||
public FeatureProvider getProvider(String domain) {
|
||||
return providerRepository.getProvider(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Adds hooks for globally, used for all evaluations.
|
||||
* Hooks are run in the order they're added in the before stage. They are run in reverse order for all other stages.
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Fetch the hooks associated to this client.
|
||||
*
|
||||
* @return A list of {@link Hook}s.
|
||||
*/
|
||||
public List<Hook> getHooks() {
|
||||
try (AutoCloseableLock __ = lock.readLockAutoCloseable()) {
|
||||
return this.apiHooks;
|
||||
}
|
||||
return new ArrayList<>(this.apiHooks);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* 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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,11 +339,11 @@ 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();
|
||||
|
||||
providerRepository = new ProviderRepository();
|
||||
providerRepository = new ProviderRepository(this);
|
||||
eventSupport = new EventSupport();
|
||||
}
|
||||
}
|
||||
|
@ -328,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;
|
||||
}
|
||||
|
@ -339,62 +396,65 @@ 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 clientName, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
|
||||
eventSupport.removeClientHandler(clientName, event, handler);
|
||||
void removeHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
|
||||
eventSupport.removeClientHandler(domain, event, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void addHandler(String clientName, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
|
||||
void addHandler(String domain, ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
try (AutoCloseableLock ignored = lock.writeLockAutoCloseable()) {
|
||||
// if the provider is in the state associated with event, run immediately
|
||||
if (Optional.ofNullable(this.providerRepository.getProvider(clientName).getState())
|
||||
.orElse(ProviderState.READY).matchesEvent(event)) {
|
||||
eventSupport.runHandler(handler, EventDetails.builder().clientName(clientName).build());
|
||||
if (Optional.ofNullable(this.providerRepository.getProviderState(domain))
|
||||
.orElse(ProviderState.READY)
|
||||
.matchesEvent(event)) {
|
||||
eventSupport.runHandler(
|
||||
handler, EventDetails.builder().domain(domain).build());
|
||||
}
|
||||
eventSupport.addClientHandler(clientName, event, handler);
|
||||
eventSupport.addClientHandler(domain, event, handler);
|
||||
}
|
||||
}
|
||||
|
||||
FeatureProviderStateManager getFeatureProviderStateManager(String domain) {
|
||||
return providerRepository.getFeatureProviderStateManager(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the handlers associated with a particular provider.
|
||||
*
|
||||
*
|
||||
* @param provider the provider from where this event originated
|
||||
* @param event the event type
|
||||
* @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> clientNamesForProvider = providerRepository
|
||||
.getClientNamesForProvider(provider);
|
||||
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 named clients for this provider
|
||||
clientNamesForProvider.forEach(name -> {
|
||||
eventSupport.runClientHandlers(name, event,
|
||||
EventDetails.fromProviderEventDetails(details, providerName, name));
|
||||
});
|
||||
// run the handlers associated with domains for this provider
|
||||
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> allClientNames = eventSupport.getAllClientNames();
|
||||
Set<String> boundClientNames = providerRepository.getAllBoundClientNames();
|
||||
allClientNames.removeAll(boundClientNames);
|
||||
allClientNames.forEach(name -> {
|
||||
eventSupport.runClientHandlers(name, event,
|
||||
EventDetails.fromProviderEventDetails(details, providerName, name));
|
||||
});
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,65 +1,130 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.ExceptionUtils;
|
||||
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.ObjectUtils;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
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 dev.openfeature.sdk.exceptions.GeneralError;
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
import dev.openfeature.sdk.internal.AutoCloseableLock;
|
||||
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
|
||||
import dev.openfeature.sdk.internal.ObjectUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* OpenFeature Client implementation.
|
||||
* You should not instantiate this or reference this class.
|
||||
* Use the dev.openfeature.sdk.Client interface instead.
|
||||
*
|
||||
* @see Client
|
||||
* @deprecated // TODO: eventually we will make this non-public. See issue #872
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.BeanMembersShouldSerialize", "unchecked", "rawtypes" })
|
||||
@SuppressWarnings({
|
||||
"PMD.DataflowAnomalyAnalysis",
|
||||
"PMD.BeanMembersShouldSerialize",
|
||||
"PMD.UnusedLocalVariable",
|
||||
"unchecked",
|
||||
"rawtypes"
|
||||
})
|
||||
@Deprecated() // TODO: eventually we will make this non-public. See issue #872
|
||||
public class OpenFeatureClient implements Client {
|
||||
|
||||
private final OpenFeatureAPI openfeatureApi;
|
||||
|
||||
@Getter
|
||||
private final String name;
|
||||
private final String domain;
|
||||
|
||||
@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.
|
||||
*
|
||||
* @param openFeatureAPI Backing global singleton
|
||||
* @param name Name of the client (used by observability tools).
|
||||
* @param domain An identifier which logically binds clients with
|
||||
* providers (used by observability tools).
|
||||
* @param version Version of the client (used by observability tools).
|
||||
* @deprecated Do not use this constructor. It's for internal use only.
|
||||
* Clients created using it will not run event handlers.
|
||||
* Use the OpenFeatureAPI's getClient factory method instead.
|
||||
* Clients created using it will not run event handlers.
|
||||
* Use the OpenFeatureAPI's getClient factory method instead.
|
||||
*/
|
||||
@Deprecated() // TODO: eventually we will make this non-public. See issue #872
|
||||
public OpenFeatureClient(OpenFeatureAPI openFeatureAPI, String name, String version) {
|
||||
public OpenFeatureClient(OpenFeatureAPI openFeatureAPI, String domain, String version) {
|
||||
this.openfeatureApi = openFeatureAPI;
|
||||
this.name = name;
|
||||
this.domain = domain;
|
||||
this.version = version;
|
||||
this.clientHooks = new ArrayList<>();
|
||||
this.clientHooks = new ConcurrentLinkedQueue<>();
|
||||
this.hookSupport = new HookSupport();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ProviderState getProviderState() {
|
||||
return openfeatureApi.getFeatureProviderStateManager(domain).getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void track(String trackingEventName) {
|
||||
validateTrackingEventName(trackingEventName);
|
||||
invokeTrack(trackingEventName, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void track(String trackingEventName, EvaluationContext context) {
|
||||
validateTrackingEventName(trackingEventName);
|
||||
Objects.requireNonNull(context);
|
||||
invokeTrack(trackingEventName, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void track(String trackingEventName, TrackingEventDetails details) {
|
||||
validateTrackingEventName(trackingEventName);
|
||||
Objects.requireNonNull(details);
|
||||
invokeTrack(trackingEventName, null, details);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void track(String trackingEventName, EvaluationContext context, TrackingEventDetails details) {
|
||||
validateTrackingEventName(trackingEventName);
|
||||
Objects.requireNonNull(context);
|
||||
Objects.requireNonNull(details);
|
||||
invokeTrack(trackingEventName, mergeEvaluationContext(context), details);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
|
||||
|
@ -68,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,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;
|
||||
}
|
||||
|
||||
|
@ -89,46 +150,70 @@ public class OpenFeatureClient implements Client {
|
|||
*/
|
||||
@Override
|
||||
public EvaluationContext getEvaluationContext() {
|
||||
try (AutoCloseableLock __ = contextLock.readLockAutoCloseable()) {
|
||||
return this.evaluationContext;
|
||||
}
|
||||
return this.evaluationContext.get();
|
||||
}
|
||||
|
||||
private <T> FlagEvaluationDetails<T> evaluateFlag(FlagValueType type, String key, T defaultValue,
|
||||
EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
FlagEvaluationOptions flagOptions = ObjectUtils.defaultIfNull(options,
|
||||
() -> FlagEvaluationOptions.builder().build());
|
||||
Map<String, Object> hints = Collections.unmodifiableMap(flagOptions.getHookHints());
|
||||
ctx = ObjectUtils.defaultIfNull(ctx, () -> new ImmutableContext());
|
||||
@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) {
|
||||
var flagOptions = ObjectUtils.defaultIfNull(
|
||||
options, () -> FlagEvaluationOptions.builder().build());
|
||||
var hints = Collections.unmodifiableMap(flagOptions.getHookHints());
|
||||
|
||||
FlagEvaluationDetails<T> details = null;
|
||||
List<Hook> mergedHooks = null;
|
||||
HookContext<T> hookCtx = null;
|
||||
FeatureProvider provider;
|
||||
HookContext<T> afterHookContext = null;
|
||||
|
||||
try {
|
||||
// openfeatureApi.getProvider() must be called once to maintain a consistent reference
|
||||
provider = openfeatureApi.getProvider(this.name);
|
||||
var stateManager = openfeatureApi.getFeatureProviderStateManager(this.domain);
|
||||
// provider must be accessed once to maintain a consistent reference
|
||||
var provider = stateManager.getProvider();
|
||||
var state = stateManager.getState();
|
||||
|
||||
mergedHooks = ObjectUtils.merge(provider.getProviderHooks(), flagOptions.getHooks(), clientHooks,
|
||||
openfeatureApi.getHooks());
|
||||
mergedHooks = ObjectUtils.merge(
|
||||
provider.getProviderHooks(), flagOptions.getHooks(), clientHooks, openfeatureApi.getMutableHooks());
|
||||
|
||||
hookCtx = HookContext.from(key, type, this.getMetadata(),
|
||||
provider.getMetadata(), ctx, defaultValue);
|
||||
var mergedCtx = hookSupport.beforeHooks(
|
||||
type,
|
||||
HookContext.from(
|
||||
key,
|
||||
type,
|
||||
this.getMetadata(),
|
||||
provider.getMetadata(),
|
||||
mergeEvaluationContext(ctx),
|
||||
defaultValue),
|
||||
mergedHooks,
|
||||
hints);
|
||||
|
||||
EvaluationContext ctxFromHook = hookSupport.beforeHooks(type, hookCtx, mergedHooks, hints);
|
||||
afterHookContext =
|
||||
HookContext.from(key, type, this.getMetadata(), provider.getMetadata(), mergedCtx, defaultValue);
|
||||
|
||||
EvaluationContext mergedCtx = mergeEvaluationContext(ctxFromHook, ctx);
|
||||
// "short circuit" if the provider is in NOT_READY or FATAL state
|
||||
if (ProviderState.NOT_READY.equals(state)) {
|
||||
throw new ProviderNotReadyError("Provider not yet initialized");
|
||||
}
|
||||
if (ProviderState.FATAL.equals(state)) {
|
||||
throw new FatalError("Provider is in an irrecoverable error state");
|
||||
}
|
||||
|
||||
ProviderEvaluation<T> providerEval = (ProviderEvaluation<T>) createProviderEvaluation(type, key,
|
||||
defaultValue, provider, mergedCtx);
|
||||
var providerEval =
|
||||
(ProviderEvaluation<T>) createProviderEvaluation(type, key, defaultValue, provider, mergedCtx);
|
||||
|
||||
details = FlagEvaluationDetails.from(providerEval, key);
|
||||
hookSupport.afterHooks(type, hookCtx, details, mergedHooks, hints);
|
||||
if (details.getErrorCode() != null) {
|
||||
var error =
|
||||
ExceptionUtils.instantiateErrorByErrorCode(details.getErrorCode(), details.getErrorMessage());
|
||||
enrichDetailsWithErrorDefaults(defaultValue, details);
|
||||
hookSupport.errorHooks(type, afterHookContext, error, mergedHooks, hints);
|
||||
} else {
|
||||
hookSupport.afterHooks(type, afterHookContext, details, mergedHooks, hints);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to correctly evaluate flag with key '{}'", key, e);
|
||||
if (details == null) {
|
||||
details = FlagEvaluationDetails.<T>builder().build();
|
||||
details = FlagEvaluationDetails.<T>builder().flagKey(key).build();
|
||||
}
|
||||
if (e instanceof OpenFeatureError) {
|
||||
details.setErrorCode(((OpenFeatureError) e).getErrorCode());
|
||||
|
@ -136,37 +221,58 @@ public class OpenFeatureClient implements Client {
|
|||
details.setErrorCode(ErrorCode.GENERAL);
|
||||
}
|
||||
details.setErrorMessage(e.getMessage());
|
||||
details.setValue(defaultValue);
|
||||
details.setReason(Reason.ERROR.toString());
|
||||
hookSupport.errorHooks(type, hookCtx, e, mergedHooks, hints);
|
||||
enrichDetailsWithErrorDefaults(defaultValue, details);
|
||||
hookSupport.errorHooks(type, afterHookContext, e, mergedHooks, hints);
|
||||
} finally {
|
||||
hookSupport.afterAllHooks(type, hookCtx, mergedHooks, hints);
|
||||
hookSupport.afterAllHooks(type, afterHookContext, details, mergedHooks, hints);
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
private static <T> void enrichDetailsWithErrorDefaults(T defaultValue, FlagEvaluationDetails<T> details) {
|
||||
details.setValue(defaultValue);
|
||||
details.setReason(Reason.ERROR.toString());
|
||||
}
|
||||
|
||||
private static void validateTrackingEventName(String str) {
|
||||
Objects.requireNonNull(str);
|
||||
if (str.isEmpty()) {
|
||||
throw new IllegalArgumentException("trackingEventName cannot be empty");
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeTrack(String trackingEventName, EvaluationContext context, TrackingEventDetails details) {
|
||||
openfeatureApi
|
||||
.getFeatureProviderStateManager(domain)
|
||||
.getProvider()
|
||||
.track(trackingEventName, mergeEvaluationContext(context), details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge hook and invocation contexts with API, transaction and client contexts.
|
||||
* Merge invocation contexts with API, transaction and client contexts.
|
||||
* Does not merge before context.
|
||||
*
|
||||
* @param hookContext hook context
|
||||
* @param invocationContext invocation context
|
||||
* @return merged evaluation context
|
||||
*/
|
||||
private EvaluationContext mergeEvaluationContext(
|
||||
EvaluationContext hookContext,
|
||||
EvaluationContext invocationContext) {
|
||||
final EvaluationContext apiContext = openfeatureApi.getEvaluationContext() != null
|
||||
? openfeatureApi.getEvaluationContext()
|
||||
: new ImmutableContext();
|
||||
final EvaluationContext clientContext = this.getEvaluationContext() != null
|
||||
? this.getEvaluationContext()
|
||||
: new ImmutableContext();
|
||||
final EvaluationContext transactionContext = openfeatureApi.getTransactionContext() != null
|
||||
? openfeatureApi.getTransactionContext()
|
||||
: new ImmutableContext();
|
||||
private EvaluationContext mergeEvaluationContext(EvaluationContext invocationContext) {
|
||||
final EvaluationContext apiContext = openfeatureApi.getEvaluationContext();
|
||||
final EvaluationContext clientContext = evaluationContext.get();
|
||||
final EvaluationContext transactionContext = openfeatureApi.getTransactionContext();
|
||||
return mergeContextMaps(apiContext, transactionContext, clientContext, invocationContext);
|
||||
}
|
||||
|
||||
return apiContext.merge(transactionContext.merge(clientContext.merge(invocationContext.merge(hookContext))));
|
||||
private EvaluationContext mergeContextMaps(EvaluationContext... contexts) {
|
||||
// avoid any unnecessary context instantiations and stream usage here; this is
|
||||
// called with every evaluation.
|
||||
Map merged = new HashMap<>();
|
||||
for (EvaluationContext evaluationContext : contexts) {
|
||||
if (evaluationContext != null && !evaluationContext.isEmpty()) {
|
||||
EvaluationContext.mergeMaps(ImmutableStructure::new, merged, evaluationContext.asUnmodifiableMap());
|
||||
}
|
||||
}
|
||||
return new ImmutableContext(merged);
|
||||
}
|
||||
|
||||
private <T> ProviderEvaluation<?> createProviderEvaluation(
|
||||
|
@ -202,8 +308,8 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBooleanValue(String key, Boolean defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public Boolean getBooleanValue(
|
||||
String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return getBooleanDetails(key, defaultValue, ctx, options).getValue();
|
||||
}
|
||||
|
||||
|
@ -214,12 +320,13 @@ public class OpenFeatureClient implements Client {
|
|||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Boolean> getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx) {
|
||||
return getBooleanDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
return getBooleanDetails(
|
||||
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Boolean> getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public FlagEvaluationDetails<Boolean> getBooleanDetails(
|
||||
String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.BOOLEAN, key, defaultValue, ctx, options);
|
||||
}
|
||||
|
||||
|
@ -234,8 +341,8 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getStringValue(String key, String defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public String getStringValue(
|
||||
String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return getStringDetails(key, defaultValue, ctx, options).getValue();
|
||||
}
|
||||
|
||||
|
@ -246,12 +353,13 @@ public class OpenFeatureClient implements Client {
|
|||
|
||||
@Override
|
||||
public FlagEvaluationDetails<String> getStringDetails(String key, String defaultValue, EvaluationContext ctx) {
|
||||
return getStringDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
return getStringDetails(
|
||||
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlagEvaluationDetails<String> getStringDetails(String key, String defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public FlagEvaluationDetails<String> getStringDetails(
|
||||
String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.STRING, key, defaultValue, ctx, options);
|
||||
}
|
||||
|
||||
|
@ -266,8 +374,8 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Integer getIntegerValue(String key, Integer defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public Integer getIntegerValue(
|
||||
String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return getIntegerDetails(key, defaultValue, ctx, options).getValue();
|
||||
}
|
||||
|
||||
|
@ -278,12 +386,13 @@ public class OpenFeatureClient implements Client {
|
|||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx) {
|
||||
return getIntegerDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
return getIntegerDetails(
|
||||
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public FlagEvaluationDetails<Integer> getIntegerDetails(
|
||||
String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.INTEGER, key, defaultValue, ctx, options);
|
||||
}
|
||||
|
||||
|
@ -298,9 +407,10 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Double getDoubleValue(String key, Double defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.DOUBLE, key, defaultValue, ctx, options).getValue();
|
||||
public Double getDoubleValue(
|
||||
String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.DOUBLE, key, defaultValue, ctx, options)
|
||||
.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -314,8 +424,8 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Double> getDoubleDetails(String key, Double defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public FlagEvaluationDetails<Double> getDoubleDetails(
|
||||
String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.DOUBLE, key, defaultValue, ctx, options);
|
||||
}
|
||||
|
||||
|
@ -330,8 +440,7 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Value getObjectValue(String key, Value defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public Value getObjectValue(String key, Value defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return getObjectDetails(key, defaultValue, ctx, options).getValue();
|
||||
}
|
||||
|
||||
|
@ -341,20 +450,20 @@ public class OpenFeatureClient implements Client {
|
|||
}
|
||||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue,
|
||||
EvaluationContext ctx) {
|
||||
return getObjectDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
public FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue, EvaluationContext ctx) {
|
||||
return getObjectDetails(
|
||||
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue, EvaluationContext ctx,
|
||||
FlagEvaluationOptions options) {
|
||||
public FlagEvaluationDetails<Value> getObjectDetails(
|
||||
String key, Value defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||
return this.evaluateFlag(FlagValueType.OBJECT, key, defaultValue, ctx, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata() {
|
||||
return () -> name;
|
||||
public ClientMetadata getMetadata() {
|
||||
return () -> domain;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,7 +503,7 @@ public class OpenFeatureClient implements Client {
|
|||
*/
|
||||
@Override
|
||||
public Client on(ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
OpenFeatureAPI.getInstance().addHandler(name, event, handler);
|
||||
openfeatureApi.addHandler(domain, event, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -403,7 +512,7 @@ public class OpenFeatureClient implements Client {
|
|||
*/
|
||||
@Override
|
||||
public Client removeHandler(ProviderEvent event, Consumer<EventDetails> handler) {
|
||||
OpenFeatureAPI.getInstance().removeHandler(name, event, handler);
|
||||
openfeatureApi.removeHandler(domain, event, handler);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ public class ProviderEvaluation<T> implements BaseEvaluation<T> {
|
|||
private String reason;
|
||||
ErrorCode errorCode;
|
||||
private String errorMessage;
|
||||
|
||||
@Builder.Default
|
||||
private ImmutableMetadata flagMetadata = ImmutableMetadata.builder().build();
|
||||
}
|
||||
|
|
|
@ -4,5 +4,8 @@ package dev.openfeature.sdk;
|
|||
* Provider event types.
|
||||
*/
|
||||
public enum ProviderEvent {
|
||||
PROVIDER_READY, PROVIDER_CONFIGURATION_CHANGED, PROVIDER_ERROR, PROVIDER_STALE;
|
||||
PROVIDER_READY,
|
||||
PROVIDER_CONFIGURATION_CHANGED,
|
||||
PROVIDER_ERROR,
|
||||
PROVIDER_STALE;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* The details of a particular event.
|
||||
*/
|
||||
@Data @SuperBuilder(toBuilder = true)
|
||||
@Data
|
||||
@SuperBuilder(toBuilder = true)
|
||||
public class ProviderEventDetails {
|
||||
private List<String> flagsChanged;
|
||||
private String message;
|
||||
private ImmutableMetadata eventMetadata;
|
||||
private ErrorCode errorCode;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.GeneralError;
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
@ -12,47 +14,97 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.GeneralError;
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
class ProviderRepository {
|
||||
|
||||
private final Map<String, FeatureProvider> providers = new ConcurrentHashMap<>();
|
||||
private final AtomicReference<FeatureProvider> defaultProvider = new AtomicReference<>(new NoOpProvider());
|
||||
private final Map<String, FeatureProviderStateManager> stateManagers = new ConcurrentHashMap<>();
|
||||
private final AtomicReference<FeatureProviderStateManager> defaultStateManger =
|
||||
new AtomicReference<>(new FeatureProviderStateManager(new NoOpProvider()));
|
||||
private final ExecutorService taskExecutor = Executors.newCachedThreadPool(runnable -> {
|
||||
final Thread thread = new Thread(runnable);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
private final Object registerStateManagerLock = new Object();
|
||||
private final OpenFeatureAPI openFeatureAPI;
|
||||
|
||||
public ProviderRepository(OpenFeatureAPI openFeatureAPI) {
|
||||
this.openFeatureAPI = openFeatureAPI;
|
||||
}
|
||||
|
||||
FeatureProviderStateManager getFeatureProviderStateManager() {
|
||||
return defaultStateManger.get();
|
||||
}
|
||||
|
||||
FeatureProviderStateManager getFeatureProviderStateManager(String domain) {
|
||||
if (domain == null) {
|
||||
return defaultStateManger.get();
|
||||
}
|
||||
FeatureProviderStateManager fromMap = this.stateManagers.get(domain);
|
||||
if (fromMap == null) {
|
||||
return this.defaultStateManger.get();
|
||||
} else {
|
||||
return fromMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default provider.
|
||||
*/
|
||||
public FeatureProvider getProvider() {
|
||||
return defaultProvider.get();
|
||||
return defaultStateManger.get().getProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a provider for a named client. If not found, return the default.
|
||||
* Fetch a provider for a domain. If not found, return the default.
|
||||
*
|
||||
* @param name The client name to look for.
|
||||
* @param domain The domain to look for.
|
||||
* @return A named {@link FeatureProvider}
|
||||
*/
|
||||
public FeatureProvider getProvider(String name) {
|
||||
return Optional.ofNullable(name).map(this.providers::get).orElse(this.defaultProvider.get());
|
||||
public FeatureProvider getProvider(String domain) {
|
||||
return getFeatureProviderStateManager(domain).getProvider();
|
||||
}
|
||||
|
||||
public List<String> getClientNamesForProvider(FeatureProvider provider) {
|
||||
return providers.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().equals(provider))
|
||||
.map(entry -> entry.getKey()).collect(Collectors.toList());
|
||||
public ProviderState getProviderState() {
|
||||
return getFeatureProviderStateManager().getState();
|
||||
}
|
||||
|
||||
public Set<String> getAllBoundClientNames() {
|
||||
return providers.keySet();
|
||||
public ProviderState getProviderState(FeatureProvider featureProvider) {
|
||||
if (featureProvider instanceof FeatureProviderStateManager) {
|
||||
return ((FeatureProviderStateManager) featureProvider).getState();
|
||||
}
|
||||
|
||||
FeatureProviderStateManager defaultProvider = this.defaultStateManger.get();
|
||||
if (defaultProvider.hasSameProvider(featureProvider)) {
|
||||
return defaultProvider.getState();
|
||||
}
|
||||
|
||||
for (FeatureProviderStateManager wrapper : stateManagers.values()) {
|
||||
if (wrapper.hasSameProvider(featureProvider)) {
|
||||
return wrapper.getState();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ProviderState getProviderState(String domain) {
|
||||
return Optional.ofNullable(domain)
|
||||
.map(this.stateManagers::get)
|
||||
.orElse(this.defaultStateManger.get())
|
||||
.getState();
|
||||
}
|
||||
|
||||
public List<String> getDomainsForProvider(FeatureProvider provider) {
|
||||
return stateManagers.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().hasSameProvider(provider))
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Set<String> getAllBoundDomains() {
|
||||
return stateManagers.keySet();
|
||||
}
|
||||
|
||||
public boolean isDefaultProvider(FeatureProvider provider) {
|
||||
|
@ -62,7 +114,8 @@ class ProviderRepository {
|
|||
/**
|
||||
* Set the default provider.
|
||||
*/
|
||||
public void setProvider(FeatureProvider provider,
|
||||
public void setProvider(
|
||||
FeatureProvider provider,
|
||||
Consumer<FeatureProvider> afterSet,
|
||||
Consumer<FeatureProvider> afterInit,
|
||||
Consumer<FeatureProvider> afterShutdown,
|
||||
|
@ -75,14 +128,15 @@ class ProviderRepository {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a provider for a named client.
|
||||
* Add a provider for a domain.
|
||||
*
|
||||
* @param clientName The name of the client.
|
||||
* @param domain The domain to bind the provider to.
|
||||
* @param provider The provider to set.
|
||||
* @param waitForInit When true, wait for initialization to finish, then returns.
|
||||
* Otherwise, initialization happens in the background.
|
||||
*/
|
||||
public void setProvider(String clientName,
|
||||
public void setProvider(
|
||||
String domain,
|
||||
FeatureProvider provider,
|
||||
Consumer<FeatureProvider> afterSet,
|
||||
Consumer<FeatureProvider> afterInit,
|
||||
|
@ -92,75 +146,113 @@ class ProviderRepository {
|
|||
if (provider == null) {
|
||||
throw new IllegalArgumentException("Provider cannot be null");
|
||||
}
|
||||
if (clientName == null) {
|
||||
throw new IllegalArgumentException("clientName cannot be null");
|
||||
if (domain == null) {
|
||||
throw new IllegalArgumentException("domain cannot be null");
|
||||
}
|
||||
prepareAndInitializeProvider(clientName, provider, afterSet, afterInit, afterShutdown, afterError, waitForInit);
|
||||
prepareAndInitializeProvider(domain, provider, afterSet, afterInit, afterShutdown, afterError, waitForInit);
|
||||
}
|
||||
|
||||
private void prepareAndInitializeProvider(String clientName,
|
||||
FeatureProvider newProvider,
|
||||
Consumer<FeatureProvider> afterSet,
|
||||
Consumer<FeatureProvider> afterInit,
|
||||
Consumer<FeatureProvider> afterShutdown,
|
||||
BiConsumer<FeatureProvider, OpenFeatureError> afterError,
|
||||
boolean waitForInit) {
|
||||
private void prepareAndInitializeProvider(
|
||||
String domain,
|
||||
FeatureProvider newProvider,
|
||||
Consumer<FeatureProvider> afterSet,
|
||||
Consumer<FeatureProvider> afterInit,
|
||||
Consumer<FeatureProvider> afterShutdown,
|
||||
BiConsumer<FeatureProvider, OpenFeatureError> afterError,
|
||||
boolean waitForInit) {
|
||||
final FeatureProviderStateManager newStateManager;
|
||||
final FeatureProviderStateManager oldStateManager;
|
||||
|
||||
if (!isProviderRegistered(newProvider)) {
|
||||
// only run afterSet if new provider is not already attached
|
||||
afterSet.accept(newProvider);
|
||||
synchronized (registerStateManagerLock) {
|
||||
FeatureProviderStateManager existing = getExistingStateManagerForProvider(newProvider);
|
||||
if (existing == null) {
|
||||
newStateManager = new FeatureProviderStateManager(newProvider);
|
||||
// only run afterSet if new provider is not already attached
|
||||
afterSet.accept(newProvider);
|
||||
} else {
|
||||
newStateManager = existing;
|
||||
}
|
||||
|
||||
// provider is set immediately, on this thread
|
||||
oldStateManager = domain != null
|
||||
? this.stateManagers.put(domain, newStateManager)
|
||||
: this.defaultStateManger.getAndSet(newStateManager);
|
||||
}
|
||||
|
||||
// provider is set immediately, on this thread
|
||||
FeatureProvider oldProvider = clientName != null
|
||||
? this.providers.put(clientName, newProvider)
|
||||
: this.defaultProvider.getAndSet(newProvider);
|
||||
|
||||
if (waitForInit) {
|
||||
initializeProvider(newProvider, afterInit, afterShutdown, afterError, oldProvider);
|
||||
initializeProvider(newStateManager, afterInit, afterShutdown, afterError, oldStateManager);
|
||||
} else {
|
||||
taskExecutor.submit(() -> {
|
||||
// initialization happens in a different thread if we're not waiting it
|
||||
initializeProvider(newProvider, afterInit, afterShutdown, afterError, oldProvider);
|
||||
// initialization happens in a different thread if we're not waiting for it
|
||||
initializeProvider(newStateManager, afterInit, afterShutdown, afterError, oldStateManager);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeProvider(FeatureProvider newProvider,
|
||||
private FeatureProviderStateManager getExistingStateManagerForProvider(FeatureProvider provider) {
|
||||
for (FeatureProviderStateManager stateManager : stateManagers.values()) {
|
||||
if (stateManager.hasSameProvider(provider)) {
|
||||
return stateManager;
|
||||
}
|
||||
}
|
||||
FeatureProviderStateManager defaultFeatureProviderStateManager = defaultStateManger.get();
|
||||
if (defaultFeatureProviderStateManager.hasSameProvider(provider)) {
|
||||
return defaultFeatureProviderStateManager;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initializeProvider(
|
||||
FeatureProviderStateManager newManager,
|
||||
Consumer<FeatureProvider> afterInit,
|
||||
Consumer<FeatureProvider> afterShutdown,
|
||||
BiConsumer<FeatureProvider, OpenFeatureError> afterError,
|
||||
FeatureProvider oldProvider) {
|
||||
FeatureProviderStateManager oldManager) {
|
||||
try {
|
||||
if (ProviderState.NOT_READY.equals(newProvider.getState())) {
|
||||
newProvider.initialize(OpenFeatureAPI.getInstance().getEvaluationContext());
|
||||
afterInit.accept(newProvider);
|
||||
if (ProviderState.NOT_READY.equals(newManager.getState())) {
|
||||
newManager.initialize(openFeatureAPI.getEvaluationContext());
|
||||
afterInit.accept(newManager.getProvider());
|
||||
}
|
||||
shutDownOld(oldProvider, afterShutdown);
|
||||
shutDownOld(oldManager, afterShutdown);
|
||||
} catch (OpenFeatureError e) {
|
||||
log.error("Exception when initializing feature provider {}", newProvider.getClass().getName(), e);
|
||||
afterError.accept(newProvider, e);
|
||||
log.error(
|
||||
"Exception when initializing feature provider {}",
|
||||
newManager.getProvider().getClass().getName(),
|
||||
e);
|
||||
afterError.accept(newManager.getProvider(), e);
|
||||
} catch (Exception e) {
|
||||
log.error("Exception when initializing feature provider {}", newProvider.getClass().getName(), e);
|
||||
afterError.accept(newProvider, new GeneralError(e));
|
||||
log.error(
|
||||
"Exception when initializing feature provider {}",
|
||||
newManager.getProvider().getClass().getName(),
|
||||
e);
|
||||
afterError.accept(newManager.getProvider(), new GeneralError(e));
|
||||
}
|
||||
}
|
||||
|
||||
private void shutDownOld(FeatureProvider oldProvider, Consumer<FeatureProvider> afterShutdown) {
|
||||
if (!isProviderRegistered(oldProvider)) {
|
||||
shutdownProvider(oldProvider);
|
||||
afterShutdown.accept(oldProvider);
|
||||
private void shutDownOld(FeatureProviderStateManager oldManager, Consumer<FeatureProvider> afterShutdown) {
|
||||
if (oldManager != null && !isStateManagerRegistered(oldManager)) {
|
||||
shutdownProvider(oldManager);
|
||||
afterShutdown.accept(oldManager.getProvider());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to check if provider is already known (registered).
|
||||
* @param provider provider to check for registration
|
||||
* Helper to check if manager is already known (registered).
|
||||
*
|
||||
* @param manager manager to check for registration
|
||||
* @return boolean true if already registered, false otherwise
|
||||
*/
|
||||
private boolean isProviderRegistered(FeatureProvider provider) {
|
||||
return provider != null
|
||||
&& (this.providers.containsValue(provider) || this.defaultProvider.get().equals(provider));
|
||||
private boolean isStateManagerRegistered(FeatureProviderStateManager manager) {
|
||||
return manager != null
|
||||
&& (this.stateManagers.containsValue(manager)
|
||||
|| this.defaultStateManger.get().equals(manager));
|
||||
}
|
||||
|
||||
private void shutdownProvider(FeatureProviderStateManager manager) {
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
shutdownProvider(manager.getProvider());
|
||||
}
|
||||
|
||||
private void shutdownProvider(FeatureProvider provider) {
|
||||
|
@ -168,7 +260,10 @@ class ProviderRepository {
|
|||
try {
|
||||
provider.shutdown();
|
||||
} catch (Exception e) {
|
||||
log.error("Exception when shutting down feature provider {}", provider.getClass().getName(), e);
|
||||
log.error(
|
||||
"Exception when shutting down feature provider {}",
|
||||
provider.getClass().getName(),
|
||||
e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -179,11 +274,10 @@ class ProviderRepository {
|
|||
* including the default feature provider.
|
||||
*/
|
||||
public void shutdown() {
|
||||
Stream
|
||||
.concat(Stream.of(this.defaultProvider.get()), this.providers.values().stream())
|
||||
Stream.concat(Stream.of(this.defaultStateManger.get()), this.stateManagers.values().stream())
|
||||
.distinct()
|
||||
.forEach(this::shutdownProvider);
|
||||
this.providers.clear();
|
||||
this.stateManagers.clear();
|
||||
taskExecutor.shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,15 @@ package dev.openfeature.sdk;
|
|||
* Indicates the state of the provider.
|
||||
*/
|
||||
public enum ProviderState {
|
||||
READY, NOT_READY, ERROR, STALE;
|
||||
READY,
|
||||
NOT_READY,
|
||||
ERROR,
|
||||
STALE,
|
||||
FATAL;
|
||||
|
||||
/**
|
||||
* Returns true if the passed ProviderEvent maps to this ProviderState.
|
||||
*
|
||||
*
|
||||
* @param event event to compare
|
||||
* @return boolean if matches.
|
||||
*/
|
||||
|
|
|
@ -4,5 +4,12 @@ package dev.openfeature.sdk;
|
|||
* Predefined resolution reasons.
|
||||
*/
|
||||
public enum Reason {
|
||||
DISABLED, SPLIT, TARGETING_MATCH, DEFAULT, UNKNOWN, CACHED, STATIC, ERROR
|
||||
DISABLED,
|
||||
SPLIT,
|
||||
TARGETING_MATCH,
|
||||
DEFAULT,
|
||||
UNKNOWN,
|
||||
CACHED,
|
||||
STATIC,
|
||||
ERROR
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic
|
||||
* to the lifecycle of flag evaluation.
|
||||
*
|
||||
* @see Hook
|
||||
*/
|
||||
public interface StringHook extends Hook<String> {
|
||||
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.ValueNotConvertableError;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static dev.openfeature.sdk.Value.objectToValue;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.ValueNotConvertableError;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* {@link Structure} represents a potentially nested object type which is used to represent
|
||||
* {@link Structure} represents a potentially nested object type which is used to represent
|
||||
* structured data.
|
||||
*/
|
||||
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||
public interface Structure {
|
||||
|
||||
|
||||
/**
|
||||
* Boolean indicating if this structure is empty.
|
||||
*
|
||||
* @return boolean for emptiness
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Get all keys.
|
||||
*
|
||||
|
@ -40,6 +44,13 @@ public interface Structure {
|
|||
*/
|
||||
Map<String, Value> asMap();
|
||||
|
||||
/**
|
||||
* Get all values, as a map of Values.
|
||||
*
|
||||
* @return all attributes on the structure into a Map
|
||||
*/
|
||||
Map<String, Value> asUnmodifiableMap();
|
||||
|
||||
/**
|
||||
* Get all values, with as a map of Object.
|
||||
*
|
||||
|
@ -81,54 +92,21 @@ public interface Structure {
|
|||
}
|
||||
|
||||
if (value.isList()) {
|
||||
return value.asList()
|
||||
.stream()
|
||||
.map(this::convertValue)
|
||||
.collect(Collectors.toList());
|
||||
return value.asList().stream().map(this::convertValue).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (value.isStructure()) {
|
||||
Structure s = value.asStructure();
|
||||
return s.asMap()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(),
|
||||
convertValue(entry.getValue())),
|
||||
return s.asUnmodifiableMap().entrySet().stream()
|
||||
.collect(
|
||||
HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(), convertValue(entry.getValue())),
|
||||
HashMap::putAll);
|
||||
}
|
||||
|
||||
throw new ValueNotConvertableError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively merges the base map with the overriding map.
|
||||
*
|
||||
* @param <T> Structure type
|
||||
* @param newStructure function to create the right structure
|
||||
* @param base base map to merge
|
||||
* @param overriding overriding map to merge
|
||||
* @return resulting merged map
|
||||
*/
|
||||
default <T extends Structure> Map<String, Value> merge(Function<Map<String, Value>, Structure> newStructure,
|
||||
Map<String, Value> base,
|
||||
Map<String, Value> overriding) {
|
||||
|
||||
final Map<String, Value> merged = new HashMap<>(base);
|
||||
for (Entry<String, Value> overridingEntry : overriding.entrySet()) {
|
||||
String key = overridingEntry.getKey();
|
||||
if (overridingEntry.getValue().isStructure() && merged.containsKey(key) && merged.get(key).isStructure()) {
|
||||
Structure mergedValue = merged.get(key).asStructure();
|
||||
Structure overridingValue = overridingEntry.getValue().asStructure();
|
||||
Map<String, Value> newMap = this.merge(newStructure, mergedValue.asMap(), overridingValue.asMap());
|
||||
merged.put(key, new Value(newStructure.apply(newMap)));
|
||||
} else {
|
||||
merged.put(key, overridingEntry.getValue());
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an object map to a {@link Structure} type.
|
||||
*
|
||||
|
@ -137,9 +115,9 @@ public interface Structure {
|
|||
*/
|
||||
static Structure mapToStructure(Map<String, Object> map) {
|
||||
return new MutableStructure(map.entrySet().stream()
|
||||
.collect(HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(),
|
||||
objectToValue(entry.getValue())),
|
||||
.collect(
|
||||
HashMap::new,
|
||||
(accumulated, entry) -> accumulated.put(entry.getKey(), objectToValue(entry.getValue())),
|
||||
HashMap::putAll));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
/**
|
||||
* Interface for Tracking events.
|
||||
*/
|
||||
public interface Tracking {
|
||||
/**
|
||||
* Performs tracking of a particular action or application state.
|
||||
*
|
||||
* @param trackingEventName Event name to track
|
||||
* @throws IllegalArgumentException if {@code trackingEventName} is null
|
||||
*/
|
||||
void track(String trackingEventName);
|
||||
|
||||
/**
|
||||
* Performs tracking of a particular action or application state.
|
||||
*
|
||||
* @param trackingEventName Event name to track
|
||||
* @param context Evaluation context used in flag evaluation
|
||||
* @throws IllegalArgumentException if {@code trackingEventName} is null
|
||||
*/
|
||||
void track(String trackingEventName, EvaluationContext context);
|
||||
|
||||
/**
|
||||
* Performs tracking of a particular action or application state.
|
||||
*
|
||||
* @param trackingEventName Event name to track
|
||||
* @param details Data pertinent to a particular tracking event
|
||||
* @throws IllegalArgumentException if {@code trackingEventName} is null
|
||||
*/
|
||||
void track(String trackingEventName, TrackingEventDetails details);
|
||||
|
||||
/**
|
||||
* Performs tracking of a particular action or application state.
|
||||
*
|
||||
* @param trackingEventName Event name to track
|
||||
* @param context Evaluation context used in flag evaluation
|
||||
* @param details Data pertinent to a particular tracking event
|
||||
* @throws IllegalArgumentException if {@code trackingEventName} is null
|
||||
*/
|
||||
void track(String trackingEventName, EvaluationContext context, TrackingEventDetails details);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Data pertinent to a particular tracking event.
|
||||
*/
|
||||
public interface TrackingEventDetails extends Structure {
|
||||
|
||||
/**
|
||||
* Returns the optional numeric tracking value.
|
||||
*/
|
||||
Optional<Number> getValue();
|
||||
}
|
|
@ -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>.
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import static dev.openfeature.sdk.Structure.mapToStructure;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.TypeMismatchError;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.TypeMismatchError;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.ToString;
|
||||
|
||||
import static dev.openfeature.sdk.Structure.mapToStructure;
|
||||
|
||||
/**
|
||||
* Values serve as a generic return type for structure data from providers.
|
||||
* Providers may deal in JSON, protobuf, XML or some other data-interchange format.
|
||||
|
@ -37,33 +36,34 @@ public class Value implements Cloneable {
|
|||
|
||||
/**
|
||||
* Construct a new Value with an Object.
|
||||
*
|
||||
* @param value to be wrapped.
|
||||
* @throws InstantiationException if value is not a valid type
|
||||
* (boolean, string, int, double, list, structure, instant)
|
||||
* (boolean, string, int, double, list, structure, instant)
|
||||
*/
|
||||
public Value(Object value) throws InstantiationException {
|
||||
this.innerObject = value;
|
||||
if (!this.isNull()
|
||||
&& !this.isBoolean()
|
||||
&& !this.isString()
|
||||
&& !this.isNumber()
|
||||
&& !this.isStructure()
|
||||
&& !this.isList()
|
||||
&& !this.isInstant()) {
|
||||
&& !this.isBoolean()
|
||||
&& !this.isString()
|
||||
&& !this.isNumber()
|
||||
&& !this.isStructure()
|
||||
&& !this.isList()
|
||||
&& !this.isInstant()) {
|
||||
throw new InstantiationException("Invalid value type: " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public Value(Value value) {
|
||||
this.innerObject = value.innerObject;
|
||||
this.innerObject = value.innerObject;
|
||||
}
|
||||
|
||||
public Value(Boolean value) {
|
||||
this.innerObject = value;
|
||||
this.innerObject = value;
|
||||
}
|
||||
|
||||
public Value(String value) {
|
||||
this.innerObject = value;
|
||||
this.innerObject = value;
|
||||
}
|
||||
|
||||
public Value(Integer value) {
|
||||
|
@ -71,69 +71,69 @@ public class Value implements Cloneable {
|
|||
}
|
||||
|
||||
public Value(Double value) {
|
||||
this.innerObject = value;
|
||||
this.innerObject = value;
|
||||
}
|
||||
|
||||
public Value(Structure value) {
|
||||
this.innerObject = value;
|
||||
this.innerObject = value;
|
||||
}
|
||||
|
||||
public Value(List<Value> value) {
|
||||
this.innerObject = value;
|
||||
this.innerObject = value;
|
||||
}
|
||||
|
||||
public Value(Instant value) {
|
||||
this.innerObject = value;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if this Value represents null.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isNull() {
|
||||
return this.innerObject == null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if this Value represents a Boolean.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isBoolean() {
|
||||
return this.innerObject instanceof Boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if this Value represents a String.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isString() {
|
||||
return this.innerObject instanceof String;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if this Value represents a numeric value.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isNumber() {
|
||||
return this.innerObject instanceof Number;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if this Value represents a Structure.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isStructure() {
|
||||
return this.innerObject instanceof Structure;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Check if this Value represents a List of Values.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isList() {
|
||||
|
@ -155,87 +155,88 @@ public class Value implements Cloneable {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check if this Value represents an Instant.
|
||||
*
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isInstant() {
|
||||
return this.innerObject instanceof Instant;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Retrieve the underlying Boolean value, or null.
|
||||
*
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "NP_BOOLEAN_RETURN_NULL",
|
||||
justification = "This is not a plain true/false method. It's understood it can return null.")
|
||||
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
|
||||
value = "NP_BOOLEAN_RETURN_NULL",
|
||||
justification = "This is not a plain true/false method. It's understood it can return null.")
|
||||
public Boolean asBoolean() {
|
||||
if (this.isBoolean()) {
|
||||
return (Boolean)this.innerObject;
|
||||
return (Boolean) this.innerObject;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Retrieve the underlying object.
|
||||
*
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
public Object asObject() {
|
||||
return this.innerObject;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieve the underlying String value, or null.
|
||||
*
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String asString() {
|
||||
if (this.isString()) {
|
||||
return (String)this.innerObject;
|
||||
return (String) this.innerObject;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieve the underlying numeric value as an Integer, or null.
|
||||
* If the value is not an integer, it will be rounded using Math.round().
|
||||
*
|
||||
*
|
||||
* @return Integer
|
||||
*/
|
||||
public Integer asInteger() {
|
||||
if (this.isNumber() && !this.isNull()) {
|
||||
return ((Number)this.innerObject).intValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the underlying numeric value as a Double, or null.
|
||||
*
|
||||
* @return Double
|
||||
*/
|
||||
public Double asDouble() {
|
||||
if (this.isNumber() && !isNull()) {
|
||||
return ((Number)this.innerObject).doubleValue();
|
||||
return ((Number) this.innerObject).intValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieve the underlying numeric value as a Double, or null.
|
||||
*
|
||||
* @return Double
|
||||
*/
|
||||
public Double asDouble() {
|
||||
if (this.isNumber() && !isNull()) {
|
||||
return ((Number) this.innerObject).doubleValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the underlying Structure value, or null.
|
||||
*
|
||||
*
|
||||
* @return Structure
|
||||
*/
|
||||
public Structure asStructure() {
|
||||
if (this.isStructure()) {
|
||||
return (Structure)this.innerObject;
|
||||
return (Structure) this.innerObject;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the underlying List value, or null.
|
||||
*
|
||||
|
@ -249,14 +250,14 @@ public class Value implements Cloneable {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Retrieve the underlying Instant value, or null.
|
||||
*
|
||||
*
|
||||
* @return Instant
|
||||
*/
|
||||
public Instant asInstant() {
|
||||
if (this.isInstant()) {
|
||||
return (Instant)this.innerObject;
|
||||
return (Instant) this.innerObject;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -274,7 +275,7 @@ public class Value implements Cloneable {
|
|||
return new Value(copy);
|
||||
}
|
||||
if (this.isStructure()) {
|
||||
return new Value(new ImmutableStructure(this.asStructure().asMap()));
|
||||
return new Value(new ImmutableStructure(this.asStructure().asUnmodifiableMap()));
|
||||
}
|
||||
if (this.isInstant()) {
|
||||
Instant copy = Instant.ofEpochMilli(this.asInstant().toEpochMilli());
|
||||
|
@ -305,9 +306,8 @@ public class Value implements Cloneable {
|
|||
} else if (object instanceof Structure) {
|
||||
return new Value((Structure) object);
|
||||
} else if (object instanceof List) {
|
||||
return new Value(((List<Object>) object).stream()
|
||||
.map(o -> objectToValue(o))
|
||||
.collect(Collectors.toList()));
|
||||
return new Value(
|
||||
((List<Object>) object).stream().map(o -> objectToValue(o)).collect(Collectors.toList()));
|
||||
} else if (object instanceof Instant) {
|
||||
return new Value((Instant) object);
|
||||
} else if (object instanceof Map) {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package dev.openfeature.sdk.exceptions;
|
||||
|
||||
import dev.openfeature.sdk.ErrorCode;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
@UtilityClass
|
||||
public class ExceptionUtils {
|
||||
|
||||
/**
|
||||
* Creates an Error for the specific error code.
|
||||
*
|
||||
* @param errorCode the ErrorCode to use
|
||||
* @param errorMessage the error message to include in the returned error
|
||||
* @return the specific OpenFeatureError for the errorCode
|
||||
*/
|
||||
public static OpenFeatureError instantiateErrorByErrorCode(ErrorCode errorCode, String errorMessage) {
|
||||
switch (errorCode) {
|
||||
case FLAG_NOT_FOUND:
|
||||
return new FlagNotFoundError(errorMessage);
|
||||
case PARSE_ERROR:
|
||||
return new ParseError(errorMessage);
|
||||
case TYPE_MISMATCH:
|
||||
return new TypeMismatchError(errorMessage);
|
||||
case TARGETING_KEY_MISSING:
|
||||
return new TargetingKeyMissingError(errorMessage);
|
||||
case INVALID_CONTEXT:
|
||||
return new InvalidContextError(errorMessage);
|
||||
case PROVIDER_NOT_READY:
|
||||
return new ProviderNotReadyError(errorMessage);
|
||||
default:
|
||||
return new GeneralError(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package dev.openfeature.sdk.exceptions;
|
||||
|
||||
import dev.openfeature.sdk.ErrorCode;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
@StandardException
|
||||
public class FatalError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.PROVIDER_FATAL;
|
||||
}
|
|
@ -4,14 +4,11 @@ import dev.openfeature.sdk.ErrorCode;
|
|||
import lombok.Getter;
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
@SuppressWarnings({"checkstyle:MissingJavadocType", "squid:S110"})
|
||||
@StandardException
|
||||
public class FlagNotFoundError extends OpenFeatureError {
|
||||
public class FlagNotFoundError extends OpenFeatureErrorWithoutStacktrace {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Getter private final ErrorCode errorCode = ErrorCode.FLAG_NOT_FOUND;
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.FLAG_NOT_FOUND;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import lombok.experimental.StandardException;
|
|||
@StandardException
|
||||
public class GeneralError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.GENERAL;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ import lombok.experimental.StandardException;
|
|||
public class InvalidContextError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter private final ErrorCode errorCode = ErrorCode.INVALID_CONTEXT;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.INVALID_CONTEXT;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package dev.openfeature.sdk.exceptions;
|
||||
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
@StandardException
|
||||
public abstract class OpenFeatureErrorWithoutStacktrace extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,6 @@ import lombok.experimental.StandardException;
|
|||
public class ParseError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter private final ErrorCode errorCode = ErrorCode.PARSE_ERROR;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.PARSE_ERROR;
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ import dev.openfeature.sdk.ErrorCode;
|
|||
import lombok.Getter;
|
||||
import lombok.experimental.StandardException;
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
@SuppressWarnings({"checkstyle:MissingJavadocType", "squid:S110"})
|
||||
@StandardException
|
||||
public class ProviderNotReadyError extends OpenFeatureError {
|
||||
public class ProviderNotReadyError extends OpenFeatureErrorWithoutStacktrace {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Getter private final ErrorCode errorCode = ErrorCode.PROVIDER_NOT_READY;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.PROVIDER_NOT_READY;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@ import lombok.experimental.StandardException;
|
|||
public class TargetingKeyMissingError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter private final ErrorCode errorCode = ErrorCode.TARGETING_KEY_MISSING;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.TARGETING_KEY_MISSING;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ import lombok.experimental.StandardException;
|
|||
/**
|
||||
* The type of the flag value does not match the expected type.
|
||||
*/
|
||||
@SuppressWarnings({"checkstyle:MissingJavadocType", "squid:S110"})
|
||||
@StandardException
|
||||
public class TypeMismatchError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter private final ErrorCode errorCode = ErrorCode.TYPE_MISMATCH;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.TYPE_MISMATCH;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import lombok.experimental.StandardException;
|
|||
@StandardException
|
||||
public class ValueNotConvertableError extends OpenFeatureError {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter
|
||||
private final ErrorCode errorCode = ErrorCode.GENERAL;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
package dev.openfeature.sdk.hooks.logging;
|
||||
|
||||
import dev.openfeature.sdk.ErrorCode;
|
||||
import dev.openfeature.sdk.EvaluationContext;
|
||||
import dev.openfeature.sdk.FlagEvaluationDetails;
|
||||
import dev.openfeature.sdk.Hook;
|
||||
import dev.openfeature.sdk.HookContext;
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.spi.LoggingEventBuilder;
|
||||
|
||||
/**
|
||||
* A hook for logging flag evaluations.
|
||||
* Useful for debugging.
|
||||
* Flag evaluation data is logged at debug and error in before/after stages and error stages, respectively.
|
||||
*/
|
||||
@Slf4j
|
||||
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
|
||||
value = "RV_RETURN_VALUE_IGNORED",
|
||||
justification = "we can ignore return values of chainables (builders) here")
|
||||
public class LoggingHook implements Hook<Object> {
|
||||
|
||||
static final String DOMAIN_KEY = "domain";
|
||||
static final String PROVIDER_NAME_KEY = "provider_name";
|
||||
static final String FLAG_KEY_KEY = "flag_key";
|
||||
static final String DEFAULT_VALUE_KEY = "default_value";
|
||||
static final String EVALUATION_CONTEXT_KEY = "evaluation_context";
|
||||
static final String ERROR_CODE_KEY = "error_code";
|
||||
static final String ERROR_MESSAGE_KEY = "error_message";
|
||||
static final String REASON_KEY = "reason";
|
||||
static final String VARIANT_KEY = "variant";
|
||||
static final String VALUE_KEY = "value";
|
||||
|
||||
private boolean includeEvaluationContext;
|
||||
|
||||
/**
|
||||
* Construct a new LoggingHook.
|
||||
*/
|
||||
public LoggingHook() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new LoggingHook.
|
||||
*
|
||||
* @param includeEvaluationContext include a serialized evaluation context in the log message (defaults to false)
|
||||
*/
|
||||
public LoggingHook(boolean includeEvaluationContext) {
|
||||
this.includeEvaluationContext = includeEvaluationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<EvaluationContext> before(HookContext<Object> hookContext, Map<String, Object> hints) {
|
||||
LoggingEventBuilder builder = log.atDebug();
|
||||
addCommonProps(builder, hookContext);
|
||||
builder.log("Before stage");
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after(
|
||||
HookContext<Object> hookContext, FlagEvaluationDetails<Object> details, Map<String, Object> hints) {
|
||||
LoggingEventBuilder builder = log.atDebug()
|
||||
.addKeyValue(REASON_KEY, details.getReason())
|
||||
.addKeyValue(VARIANT_KEY, details.getVariant())
|
||||
.addKeyValue(VALUE_KEY, details.getValue());
|
||||
addCommonProps(builder, hookContext);
|
||||
builder.log("After stage");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(HookContext<Object> hookContext, Exception error, Map<String, Object> hints) {
|
||||
LoggingEventBuilder builder = log.atError().addKeyValue(ERROR_MESSAGE_KEY, error.getMessage());
|
||||
addCommonProps(builder, hookContext);
|
||||
ErrorCode errorCode = error instanceof OpenFeatureError ? ((OpenFeatureError) error).getErrorCode() : null;
|
||||
builder.addKeyValue(ERROR_CODE_KEY, errorCode);
|
||||
builder.log("Error stage", error);
|
||||
}
|
||||
|
||||
private void addCommonProps(LoggingEventBuilder builder, HookContext<Object> hookContext) {
|
||||
builder.addKeyValue(DOMAIN_KEY, hookContext.getClientMetadata().getDomain())
|
||||
.addKeyValue(
|
||||
PROVIDER_NAME_KEY, hookContext.getProviderMetadata().getName())
|
||||
.addKeyValue(FLAG_KEY_KEY, hookContext.getFlagKey())
|
||||
.addKeyValue(DEFAULT_VALUE_KEY, hookContext.getDefaultValue());
|
||||
|
||||
if (includeEvaluationContext) {
|
||||
builder.addKeyValue(EVALUATION_CONTEXT_KEY, hookContext.getCtx());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package dev.openfeature.sdk.internal;
|
|||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
public interface AutoCloseableLock extends AutoCloseable {
|
||||
|
||||
|
||||
/**
|
||||
* Override the exception in AutoClosable.
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,7 @@ public class AutoCloseableReentrantReadWriteLock extends ReentrantReadWriteLock
|
|||
|
||||
/**
|
||||
* Get the single write lock as an AutoCloseableLock.
|
||||
*
|
||||
* @return unlock method ref
|
||||
*/
|
||||
public AutoCloseableLock writeLockAutoCloseable() {
|
||||
|
@ -19,10 +20,11 @@ public class AutoCloseableReentrantReadWriteLock extends ReentrantReadWriteLock
|
|||
|
||||
/**
|
||||
* Get the multi read lock as an AutoCloseableLock.
|
||||
*
|
||||
* @return unlock method ref
|
||||
*/
|
||||
public AutoCloseableLock readLockAutoCloseable() {
|
||||
this.readLock().lock();
|
||||
return this.readLock()::unlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package dev.openfeature.sdk.internal;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* JaCoCo ignores coverage of methods annotated with any annotation with "generated" in the name.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface ExcludeFromGeneratedCoverageReport {}
|
|
@ -1,12 +1,10 @@
|
|||
package dev.openfeature.sdk.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@SuppressWarnings("checkstyle:MissingJavadocType")
|
||||
|
@ -15,9 +13,10 @@ public class ObjectUtils {
|
|||
|
||||
/**
|
||||
* If the source param is null, return the default value.
|
||||
* @param source maybe null object
|
||||
*
|
||||
* @param source maybe null object
|
||||
* @param defaultValue thing to use if source is null
|
||||
* @param <T> list type
|
||||
* @param <T> list type
|
||||
* @return resulting object
|
||||
*/
|
||||
public static <T> List<T> defaultIfNull(List<T> source, Supplier<List<T>> defaultValue) {
|
||||
|
@ -29,10 +28,11 @@ public class ObjectUtils {
|
|||
|
||||
/**
|
||||
* If the source param is null, return the default value.
|
||||
* @param source maybe null object
|
||||
*
|
||||
* @param source maybe null object
|
||||
* @param defaultValue thing to use if source is null
|
||||
* @param <K> map key type
|
||||
* @param <V> map value type
|
||||
* @param <K> map key type
|
||||
* @param <V> map value type
|
||||
* @return resulting map
|
||||
*/
|
||||
public static <K, V> Map<K, V> defaultIfNull(Map<K, V> source, Supplier<Map<K, V>> defaultValue) {
|
||||
|
@ -44,9 +44,10 @@ public class ObjectUtils {
|
|||
|
||||
/**
|
||||
* If the source param is null, return the default value.
|
||||
* @param source maybe null object
|
||||
*
|
||||
* @param source maybe null object
|
||||
* @param defaultValue thing to use if source is null
|
||||
* @param <T> type
|
||||
* @param <T> type
|
||||
* @return resulting object
|
||||
*/
|
||||
public static <T> T defaultIfNull(T source, Supplier<T> defaultValue) {
|
||||
|
@ -58,15 +59,17 @@ public class ObjectUtils {
|
|||
|
||||
/**
|
||||
* Concatenate a bunch of lists.
|
||||
*
|
||||
* @param sources bunch of lists.
|
||||
* @param <T> list type
|
||||
* @param <T> list type
|
||||
* @return resulting object
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static <T> List<T> merge(List<T>... sources) {
|
||||
return Arrays
|
||||
.stream(sources)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
public static <T> List<T> merge(Collection<T>... sources) {
|
||||
List<T> merged = new ArrayList<>();
|
||||
for (Collection<T> source : sources) {
|
||||
merged.addAll(source);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.util.Objects;
|
|||
|
||||
/**
|
||||
* Like {@link java.util.function.BiConsumer} but with 3 params.
|
||||
*
|
||||
*
|
||||
* @see java.util.function.BiConsumer
|
||||
*/
|
||||
@FunctionalInterface
|
||||
|
@ -35,4 +35,4 @@ public interface TriConsumer<T, U, V> {
|
|||
after.accept(t, u, v);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import dev.openfeature.sdk.EvaluationContext;
|
|||
|
||||
/**
|
||||
* Context evaluator - use for resolving flag according to evaluation context, for handling targeting.
|
||||
*
|
||||
* @param <T> expected value type
|
||||
*/
|
||||
public interface ContextEvaluator<T> {
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package dev.openfeature.sdk.providers.memory;
|
||||
|
||||
import dev.openfeature.sdk.ImmutableMetadata;
|
||||
import java.util.Map;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Singular;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Flag representation for the in-memory provider.
|
||||
*/
|
||||
|
@ -16,6 +16,8 @@ import java.util.Map;
|
|||
public class Flag<T> {
|
||||
@Singular
|
||||
private Map<String, Object> variants;
|
||||
|
||||
private String defaultVariant;
|
||||
private ContextEvaluator<T> contextEvaluator;
|
||||
private ImmutableMetadata flagMetadata;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
package dev.openfeature.sdk.providers.memory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import dev.openfeature.sdk.EvaluationContext;
|
||||
import dev.openfeature.sdk.EventProvider;
|
||||
import dev.openfeature.sdk.Metadata;
|
||||
|
@ -15,11 +8,18 @@ import dev.openfeature.sdk.ProviderEventDetails;
|
|||
import dev.openfeature.sdk.ProviderState;
|
||||
import dev.openfeature.sdk.Reason;
|
||||
import dev.openfeature.sdk.Value;
|
||||
import dev.openfeature.sdk.exceptions.FatalError;
|
||||
import dev.openfeature.sdk.exceptions.FlagNotFoundError;
|
||||
import dev.openfeature.sdk.exceptions.GeneralError;
|
||||
import dev.openfeature.sdk.exceptions.OpenFeatureError;
|
||||
import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
|
||||
import dev.openfeature.sdk.exceptions.TypeMismatchError;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -33,7 +33,7 @@ public class InMemoryProvider extends EventProvider {
|
|||
@Getter
|
||||
private static final String NAME = "InMemoryProvider";
|
||||
|
||||
private Map<String, Flag<?>> flags;
|
||||
private final Map<String, Flag<?>> flags;
|
||||
|
||||
@Getter
|
||||
private ProviderState state = ProviderState.NOT_READY;
|
||||
|
@ -44,11 +44,12 @@ public class InMemoryProvider extends EventProvider {
|
|||
}
|
||||
|
||||
public InMemoryProvider(Map<String, Flag<?>> flags) {
|
||||
this.flags = new HashMap<>(flags);
|
||||
this.flags = new ConcurrentHashMap<>(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the provider.
|
||||
* Initializes the provider.
|
||||
*
|
||||
* @param evaluationContext evaluation context
|
||||
* @throws Exception on error
|
||||
*/
|
||||
|
@ -60,72 +61,79 @@ public class InMemoryProvider extends EventProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Updating provider flags configuration, replacing existing flags.
|
||||
* @param flags the flags to use instead of the previous flags.
|
||||
* Updates the provider flags configuration.
|
||||
* For existing flags, the new configurations replace the old one.
|
||||
* For new flags, they are added to the configuration.
|
||||
*
|
||||
* @param newFlags the new flag configurations
|
||||
*/
|
||||
public void updateFlags(Map<String, Flag<?>> flags) {
|
||||
Set<String> flagsChanged = new HashSet<>();
|
||||
flagsChanged.addAll(this.flags.keySet());
|
||||
flagsChanged.addAll(flags.keySet());
|
||||
this.flags = new HashMap<>(flags);
|
||||
public void updateFlags(Map<String, Flag<?>> newFlags) {
|
||||
Set<String> flagsChanged = new HashSet<>(newFlags.keySet());
|
||||
this.flags.putAll(newFlags);
|
||||
|
||||
ProviderEventDetails details = ProviderEventDetails.builder()
|
||||
.flagsChanged(new ArrayList<>(flagsChanged))
|
||||
.message("flags changed")
|
||||
.build();
|
||||
.flagsChanged(new ArrayList<>(flagsChanged))
|
||||
.message("flags changed")
|
||||
.build();
|
||||
emitProviderConfigurationChanged(details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updating provider flags configuration with adding or updating a flag.
|
||||
* @param flag the flag to update. If a flag with this key already exists, new flag replaces it.
|
||||
* Updates a single provider flag configuration.
|
||||
* For existing flag, the new configuration replaces the old one.
|
||||
* For new flag, they are added to the configuration.
|
||||
*
|
||||
* @param newFlag the flag to update
|
||||
*/
|
||||
public void updateFlag(String flagKey, Flag<?> flag) {
|
||||
this.flags.put(flagKey, flag);
|
||||
public void updateFlag(String flagKey, Flag<?> newFlag) {
|
||||
this.flags.put(flagKey, newFlag);
|
||||
ProviderEventDetails details = ProviderEventDetails.builder()
|
||||
.flagsChanged(Arrays.asList(flagKey))
|
||||
.message("flag added/updated")
|
||||
.build();
|
||||
.flagsChanged(Collections.singletonList(flagKey))
|
||||
.message("flag added/updated")
|
||||
.build();
|
||||
emitProviderConfigurationChanged(details);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue,
|
||||
EvaluationContext evaluationContext) {
|
||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(
|
||||
String key, Boolean defaultValue, EvaluationContext evaluationContext) {
|
||||
return getEvaluation(key, evaluationContext, Boolean.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue,
|
||||
EvaluationContext evaluationContext) {
|
||||
public ProviderEvaluation<String> getStringEvaluation(
|
||||
String key, String defaultValue, EvaluationContext evaluationContext) {
|
||||
return getEvaluation(key, evaluationContext, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue,
|
||||
EvaluationContext evaluationContext) {
|
||||
public ProviderEvaluation<Integer> getIntegerEvaluation(
|
||||
String key, Integer defaultValue, EvaluationContext evaluationContext) {
|
||||
return getEvaluation(key, evaluationContext, Integer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue,
|
||||
EvaluationContext evaluationContext) {
|
||||
public ProviderEvaluation<Double> getDoubleEvaluation(
|
||||
String key, Double defaultValue, EvaluationContext evaluationContext) {
|
||||
return getEvaluation(key, evaluationContext, Double.class);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue,
|
||||
EvaluationContext evaluationContext) {
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(
|
||||
String key, Value defaultValue, EvaluationContext evaluationContext) {
|
||||
return getEvaluation(key, evaluationContext, Value.class);
|
||||
}
|
||||
|
||||
private <T> ProviderEvaluation<T> getEvaluation(
|
||||
String key, EvaluationContext evaluationContext, Class<?> expectedType
|
||||
) throws OpenFeatureError {
|
||||
String key, EvaluationContext evaluationContext, Class<?> expectedType) throws OpenFeatureError {
|
||||
if (!ProviderState.READY.equals(state)) {
|
||||
if (ProviderState.NOT_READY.equals(state)) {
|
||||
throw new ProviderNotReadyError("provider not yet initialized");
|
||||
}
|
||||
if (ProviderState.FATAL.equals(state)) {
|
||||
throw new FatalError("provider in fatal error state");
|
||||
}
|
||||
throw new GeneralError("unknown error");
|
||||
}
|
||||
Flag<?> flag = flags.get(key);
|
||||
|
@ -141,10 +149,10 @@ public class InMemoryProvider extends EventProvider {
|
|||
value = (T) flag.getVariants().get(flag.getDefaultVariant());
|
||||
}
|
||||
return ProviderEvaluation.<T>builder()
|
||||
.value(value)
|
||||
.variant(flag.getDefaultVariant())
|
||||
.reason(Reason.STATIC.toString())
|
||||
.build();
|
||||
.value(value)
|
||||
.variant(flag.getDefaultVariant())
|
||||
.reason(Reason.STATIC.toString())
|
||||
.flagMetadata(flag.getFlagMetadata())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
public class AlwaysBrokenWithDetailsProvider implements FeatureProvider {
|
||||
|
||||
private final String name = "always broken with details";
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata() {
|
||||
return () -> name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx) {
|
||||
return ProviderEvaluation.<Boolean>builder()
|
||||
.errorMessage(TestConstants.BROKEN_MESSAGE)
|
||||
.errorCode(ErrorCode.FLAG_NOT_FOUND)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx) {
|
||||
return ProviderEvaluation.<String>builder()
|
||||
.errorMessage(TestConstants.BROKEN_MESSAGE)
|
||||
.errorCode(ErrorCode.FLAG_NOT_FOUND)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx) {
|
||||
return ProviderEvaluation.<Integer>builder()
|
||||
.errorMessage(TestConstants.BROKEN_MESSAGE)
|
||||
.errorCode(ErrorCode.FLAG_NOT_FOUND)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx) {
|
||||
return ProviderEvaluation.<Double>builder()
|
||||
.errorMessage(TestConstants.BROKEN_MESSAGE)
|
||||
.errorCode(ErrorCode.FLAG_NOT_FOUND)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(
|
||||
String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
return ProviderEvaluation.<Value>builder()
|
||||
.errorMessage(TestConstants.BROKEN_MESSAGE)
|
||||
.errorCode(ErrorCode.FLAG_NOT_FOUND)
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -2,16 +2,13 @@ package dev.openfeature.sdk;
|
|||
|
||||
import dev.openfeature.sdk.exceptions.FlagNotFoundError;
|
||||
|
||||
public class AlwaysBrokenProvider implements FeatureProvider {
|
||||
public class AlwaysBrokenWithExceptionProvider implements FeatureProvider {
|
||||
|
||||
private final String name = "always broken";
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata() {
|
||||
return new Metadata() {
|
||||
@Override
|
||||
public String getName() {
|
||||
throw new FlagNotFoundError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
};
|
||||
return () -> name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,7 +32,8 @@ public class AlwaysBrokenProvider implements FeatureProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(
|
||||
String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
throw new FlagNotFoundError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.testutils.FeatureProviderTestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ClientProviderMappingTest {
|
||||
|
||||
@Test
|
||||
void clientProviderTest() {
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
OpenFeatureAPI api = new OpenFeatureAPI();
|
||||
|
||||
FeatureProviderTestUtils.setFeatureProvider("client1", new DoSomethingProvider());
|
||||
FeatureProviderTestUtils.setFeatureProvider("client2", new NoOpProvider());
|
||||
api.setProviderAndWait("client1", new DoSomethingProvider());
|
||||
api.setProviderAndWait("client2", new NoOpProvider());
|
||||
|
||||
Client c1 = api.getClient("client1");
|
||||
Client c2 = api.getClient("client2");
|
||||
|
|
|
@ -1,57 +1,67 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import dev.openfeature.sdk.fixtures.HookFixtures;
|
||||
import dev.openfeature.sdk.testutils.TestEventsProvider;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import dev.openfeature.sdk.testutils.FeatureProviderTestUtils;
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import dev.openfeature.sdk.fixtures.HookFixtures;
|
||||
|
||||
class DeveloperExperienceTest implements HookFixtures {
|
||||
transient String flagKey = "mykey";
|
||||
private OpenFeatureAPI api;
|
||||
|
||||
@Test void simpleBooleanFlag() {
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
api.setProvider(new NoOpProvider());
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
api = new OpenFeatureAPI();
|
||||
}
|
||||
|
||||
@Test
|
||||
void simpleBooleanFlag() {
|
||||
api.setProviderAndWait(new TestEventsProvider());
|
||||
Client client = api.getClient();
|
||||
Boolean retval = client.getBooleanValue(flagKey, false);
|
||||
assertFalse(retval);
|
||||
}
|
||||
|
||||
@Test void clientHooks() {
|
||||
@Test
|
||||
void clientHooks() {
|
||||
Hook<Boolean> exampleHook = mockBooleanHook();
|
||||
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
api.setProvider(new NoOpProvider());
|
||||
api.setProviderAndWait(new TestEventsProvider());
|
||||
Client client = api.getClient();
|
||||
client.addHooks(exampleHook);
|
||||
Boolean retval = client.getBooleanValue(flagKey, false);
|
||||
verify(exampleHook, times(1)).finallyAfter(any(), any());
|
||||
verify(exampleHook, times(1)).finallyAfter(any(), any(), any());
|
||||
assertFalse(retval);
|
||||
}
|
||||
|
||||
@Test void evalHooks() {
|
||||
@Test
|
||||
void evalHooks() {
|
||||
Hook<Boolean> clientHook = mockBooleanHook();
|
||||
Hook<Boolean> evalHook = mockBooleanHook();
|
||||
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
api.setProvider(new NoOpProvider());
|
||||
api.setProviderAndWait(new TestEventsProvider());
|
||||
Client client = api.getClient();
|
||||
client.addHooks(clientHook);
|
||||
Boolean retval = client.getBooleanValue(flagKey, false, null,
|
||||
Boolean retval = client.getBooleanValue(
|
||||
flagKey,
|
||||
false,
|
||||
null,
|
||||
FlagEvaluationOptions.builder().hook(evalHook).build());
|
||||
verify(clientHook, times(1)).finallyAfter(any(), any());
|
||||
verify(evalHook, times(1)).finallyAfter(any(), any());
|
||||
verify(clientHook, times(1)).finallyAfter(any(), any(), any());
|
||||
verify(evalHook, times(1)).finallyAfter(any(), any(), any());
|
||||
assertFalse(retval);
|
||||
}
|
||||
|
||||
|
@ -59,10 +69,10 @@ class DeveloperExperienceTest implements HookFixtures {
|
|||
* As an application author, you probably know special things about your users. You can communicate these to the
|
||||
* provider via {@link MutableContext}
|
||||
*/
|
||||
@Test void providingContext() {
|
||||
@Test
|
||||
void providingContext() {
|
||||
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
api.setProvider(new NoOpProvider());
|
||||
api.setProviderAndWait(new TestEventsProvider());
|
||||
Client client = api.getClient();
|
||||
Map<String, Value> attributes = new HashMap<>();
|
||||
List<Value> values = Arrays.asList(new Value(2), new Value(4));
|
||||
|
@ -76,9 +86,9 @@ class DeveloperExperienceTest implements HookFixtures {
|
|||
assertFalse(retval);
|
||||
}
|
||||
|
||||
@Test void brokenProvider() {
|
||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
FeatureProviderTestUtils.setFeatureProvider(new AlwaysBrokenProvider());
|
||||
@Test
|
||||
void brokenProvider() {
|
||||
api.setProviderAndWait(new AlwaysBrokenWithExceptionProvider());
|
||||
Client client = api.getClient();
|
||||
FlagEvaluationDetails<Boolean> retval = client.getBooleanDetails(flagKey, false);
|
||||
assertEquals(ErrorCode.FLAG_NOT_FOUND, retval.getErrorCode());
|
||||
|
@ -90,20 +100,24 @@ class DeveloperExperienceTest implements HookFixtures {
|
|||
@Test
|
||||
void providerLockedPerTransaction() {
|
||||
|
||||
final String defaultValue = "string-value";
|
||||
final OpenFeatureAPI api = new OpenFeatureAPI();
|
||||
|
||||
class MutatingHook implements Hook {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
// change the provider during a before hook - this should not impact the evaluation in progress
|
||||
public Optional before(HookContext ctx, Map hints) {
|
||||
FeatureProviderTestUtils.setFeatureProvider(new NoOpProvider());
|
||||
|
||||
api.setProviderAndWait(TestEventsProvider.newInitializedTestEventsProvider());
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
final String defaultValue = "string-value";
|
||||
final OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||
|
||||
final Client client = api.getClient();
|
||||
FeatureProviderTestUtils.setFeatureProvider(new DoSomethingProvider());
|
||||
api.setProviderAndWait(new DoSomethingProvider());
|
||||
api.addHooks(new MutatingHook());
|
||||
|
||||
// if provider is changed during an evaluation transaction it should proceed with the original provider
|
||||
|
@ -111,9 +125,64 @@ class DeveloperExperienceTest implements HookFixtures {
|
|||
assertEquals(new StringBuilder(defaultValue).reverse().toString(), doSomethingValue);
|
||||
|
||||
api.clearHooks();
|
||||
|
||||
|
||||
// subsequent evaluations should now use new provider set by hook
|
||||
String noOpValue = client.getStringValue("val", defaultValue);
|
||||
assertEquals(noOpValue, defaultValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setProviderAndWaitShouldPutTheProviderInReadyState() {
|
||||
String domain = "domain";
|
||||
api.setProviderAndWait(domain, new TestEventsProvider());
|
||||
Client client = api.getClient(domain);
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
|
||||
}
|
||||
|
||||
@Specification(
|
||||
number = "5.3.5",
|
||||
text =
|
||||
"If the provider emits an event, the value of the client's provider status MUST be updated accordingly.")
|
||||
@Test
|
||||
void shouldPutTheProviderInStateErrorAfterEmittingErrorEvent() {
|
||||
String domain = "domain";
|
||||
TestEventsProvider provider = new TestEventsProvider();
|
||||
api.setProviderAndWait(domain, provider);
|
||||
Client client = api.getClient(domain);
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
|
||||
provider.emitProviderError(ProviderEventDetails.builder().build()).await();
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.ERROR);
|
||||
}
|
||||
|
||||
@Specification(
|
||||
number = "5.3.5",
|
||||
text =
|
||||
"If the provider emits an event, the value of the client's provider status MUST be updated accordingly.")
|
||||
@Test
|
||||
void shouldPutTheProviderInStateStaleAfterEmittingStaleEvent() {
|
||||
String domain = "domain";
|
||||
TestEventsProvider provider = new TestEventsProvider();
|
||||
api.setProviderAndWait(domain, provider);
|
||||
Client client = api.getClient(domain);
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
|
||||
provider.emitProviderStale(ProviderEventDetails.builder().build()).await();
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.STALE);
|
||||
}
|
||||
|
||||
@Specification(
|
||||
number = "5.3.5",
|
||||
text =
|
||||
"If the provider emits an event, the value of the client's provider status MUST be updated accordingly.")
|
||||
@Test
|
||||
void shouldPutTheProviderInStateReadyAfterEmittingReadyEvent() {
|
||||
String domain = "domain";
|
||||
TestEventsProvider provider = new TestEventsProvider();
|
||||
api.setProviderAndWait(domain, provider);
|
||||
Client client = api.getClient(domain);
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
|
||||
provider.emitProviderStale(ProviderEventDetails.builder().build()).await();
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.STALE);
|
||||
provider.emitProviderReady(ProviderEventDetails.builder().build()).await();
|
||||
assertThat(client.getProviderState()).isEqualTo(ProviderState.READY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,10 @@ class DoSomethingProvider implements FeatureProvider {
|
|||
|
||||
static final String name = "Something";
|
||||
// Flag evaluation metadata
|
||||
static final ImmutableMetadata DEFAULT_METADATA = ImmutableMetadata.builder().build();
|
||||
static final ImmutableMetadata DEFAULT_METADATA =
|
||||
ImmutableMetadata.builder().build();
|
||||
private ImmutableMetadata flagMetadata;
|
||||
|
||||
private EvaluationContext savedContext;
|
||||
|
||||
public DoSomethingProvider() {
|
||||
this.flagMetadata = DEFAULT_METADATA;
|
||||
}
|
||||
|
@ -17,10 +16,6 @@ class DoSomethingProvider implements FeatureProvider {
|
|||
this.flagMetadata = flagMetadata;
|
||||
}
|
||||
|
||||
EvaluationContext getMergedContext() {
|
||||
return savedContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata() {
|
||||
return () -> name;
|
||||
|
@ -28,7 +23,6 @@ class DoSomethingProvider implements FeatureProvider {
|
|||
|
||||
@Override
|
||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx) {
|
||||
savedContext = ctx;
|
||||
return ProviderEvaluation.<Boolean>builder()
|
||||
.value(!defaultValue)
|
||||
.flagMetadata(flagMetadata)
|
||||
|
@ -45,7 +39,6 @@ class DoSomethingProvider implements FeatureProvider {
|
|||
|
||||
@Override
|
||||
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx) {
|
||||
savedContext = ctx;
|
||||
return ProviderEvaluation.<Integer>builder()
|
||||
.value(defaultValue * 100)
|
||||
.flagMetadata(flagMetadata)
|
||||
|
@ -54,7 +47,6 @@ class DoSomethingProvider implements FeatureProvider {
|
|||
|
||||
@Override
|
||||
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx) {
|
||||
savedContext = ctx;
|
||||
return ProviderEvaluation.<Double>builder()
|
||||
.value(defaultValue * 100)
|
||||
.flagMetadata(flagMetadata)
|
||||
|
@ -62,8 +54,8 @@ class DoSomethingProvider implements FeatureProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
savedContext = invocationContext;
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(
|
||||
String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
return ProviderEvaluation.<Value>builder()
|
||||
.value(null)
|
||||
.flagMetadata(flagMetadata)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue