5
5
import java .util .List ;
6
6
import java .util .Map ;
7
7
import java .util .Optional ;
8
- import java .util .function .Consumer ;
8
+ import java .util .function .BiConsumer ;
9
9
import lombok .RequiredArgsConstructor ;
10
10
import lombok .extern .slf4j .Slf4j ;
11
11
15
15
class HookSupport {
16
16
17
17
public EvaluationContext beforeHooks (
18
- FlagValueType flagValueType , HookContext hookCtx , List <Hook > hooks , Map <String , Object > hints ) {
19
- return callBeforeHooks (flagValueType , hookCtx , hooks , hints );
18
+ FlagValueType flagValueType ,
19
+ HookContext hookCtx ,
20
+ List <Pair <Hook , HookData >> hookDataPairs ,
21
+ Map <String , Object > hints ) {
22
+ return callBeforeHooks (flagValueType , hookCtx , hookDataPairs , hints );
20
23
}
21
24
22
25
public void afterHooks (
23
26
FlagValueType flagValueType ,
24
27
HookContext hookContext ,
25
28
FlagEvaluationDetails details ,
26
- List <Hook > hooks ,
29
+ List <Pair < Hook , HookData >> hookDataPairs ,
27
30
Map <String , Object > hints ) {
28
- executeHooksUnchecked (flagValueType , hooks , hook -> hook .after (hookContext , details , hints ));
31
+ executeHooksUnchecked (
32
+ flagValueType , hookDataPairs , hookContext , (hook , ctx ) -> hook .after (ctx , details , hints ));
29
33
}
30
34
31
35
public void afterAllHooks (
32
36
FlagValueType flagValueType ,
33
37
HookContext hookCtx ,
34
38
FlagEvaluationDetails details ,
35
- List <Hook > hooks ,
39
+ List <Pair < Hook , HookData >> hookDataPairs ,
36
40
Map <String , Object > hints ) {
37
- executeHooks (flagValueType , hooks , "finally" , hook -> hook .finallyAfter (hookCtx , details , hints ));
41
+ executeHooks (
42
+ flagValueType ,
43
+ hookDataPairs ,
44
+ hookCtx ,
45
+ "finally" ,
46
+ (hook , ctx ) -> hook .finallyAfter (ctx , details , hints ));
38
47
}
39
48
40
49
public void errorHooks (
41
50
FlagValueType flagValueType ,
42
51
HookContext hookCtx ,
43
52
Exception e ,
44
- List <Hook > hooks ,
53
+ List <Pair < Hook , HookData >> hookDataPairs ,
45
54
Map <String , Object > hints ) {
46
- executeHooks (flagValueType , hooks , "error" , hook -> hook .error (hookCtx , e , hints ));
55
+ executeHooks (flagValueType , hookDataPairs , hookCtx , "error" , (hook , ctx ) -> hook .error (ctx , e , hints ));
56
+ }
57
+
58
+ public List <Pair <Hook , HookData >> getHookDataPairs (List <Hook > hooks , FlagValueType flagValueType ) {
59
+ var pairs = new ArrayList <Pair <Hook , HookData >>();
60
+ for (Hook hook : hooks ) {
61
+ if (hook .supportsFlagValueType (flagValueType )) {
62
+ pairs .add (Pair .of (hook , HookData .create ()));
63
+ }
64
+ }
65
+ return pairs ;
47
66
}
48
67
49
68
private <T > void executeHooks (
50
- FlagValueType flagValueType , List <Hook > hooks , String hookMethod , Consumer <Hook <T >> hookCode ) {
51
- if (hooks != null ) {
52
- for (Hook hook : hooks ) {
53
- if (hook .supportsFlagValueType (flagValueType )) {
54
- executeChecked (hook , hookCode , hookMethod );
55
- }
69
+ FlagValueType flagValueType ,
70
+ List <Pair <Hook , HookData >> hookDataPairs ,
71
+ HookContext hookContext ,
72
+ String hookMethod ,
73
+ BiConsumer <Hook <T >, HookContext > hookCode ) {
74
+ if (hookDataPairs != null ) {
75
+ for (Pair <Hook , HookData > hookDataPair : hookDataPairs ) {
76
+ Hook hook = hookDataPair .getLeft ();
77
+ HookData hookData = hookDataPair .getRight ();
78
+ executeChecked (hook , hookData , hookContext , hookCode , hookMethod );
56
79
}
57
80
}
58
81
}
59
82
60
83
// before, error, and finally hooks shouldn't throw
61
- private <T > void executeChecked (Hook <T > hook , Consumer <Hook <T >> hookCode , String hookMethod ) {
84
+ private <T > void executeChecked (
85
+ Hook <T > hook ,
86
+ HookData hookData ,
87
+ HookContext hookContext ,
88
+ BiConsumer <Hook <T >, HookContext > hookCode ,
89
+ String hookMethod ) {
62
90
try {
63
- hookCode .accept (hook );
91
+ var hookCtxWithData = new HookContextWithData (hookContext , hookData );
92
+ hookCode .accept (hook , hookCtxWithData );
64
93
} catch (Exception exception ) {
65
94
log .error (
66
95
"Unhandled exception when running {} hook {} (only 'after' hooks should throw)" ,
@@ -71,29 +100,41 @@ private <T> void executeChecked(Hook<T> hook, Consumer<Hook<T>> hookCode, String
71
100
}
72
101
73
102
// after hooks can throw in order to do validation
74
- private <T > void executeHooksUnchecked (FlagValueType flagValueType , List <Hook > hooks , Consumer <Hook <T >> hookCode ) {
75
- if (hooks != null ) {
76
- for (Hook hook : hooks ) {
77
- if (hook .supportsFlagValueType (flagValueType )) {
78
- hookCode .accept (hook );
79
- }
103
+ private <T > void executeHooksUnchecked (
104
+ FlagValueType flagValueType ,
105
+ List <Pair <Hook , HookData >> hookDataPairs ,
106
+ HookContext hookContext ,
107
+ BiConsumer <Hook <T >, HookContext > hookCode ) {
108
+ if (hookDataPairs != null ) {
109
+ for (Pair <Hook , HookData > hookDataPair : hookDataPairs ) {
110
+ Hook hook = hookDataPair .getLeft ();
111
+ HookData hookData = hookDataPair .getRight ();
112
+ var hookCtxWithData = new HookContextWithData (hookContext , hookData );
113
+ hookCode .accept (hook , hookCtxWithData );
80
114
}
81
115
}
82
116
}
83
117
84
118
private EvaluationContext callBeforeHooks (
85
- FlagValueType flagValueType , HookContext hookCtx , List <Hook > hooks , Map <String , Object > hints ) {
119
+ FlagValueType flagValueType ,
120
+ HookContext hookCtx ,
121
+ List <Pair <Hook , HookData >> hookDataPairs ,
122
+ Map <String , Object > hints ) {
86
123
// These traverse backwards from normal.
87
- List <Hook > reversedHooks = new ArrayList <>(hooks );
124
+ List <Pair < Hook , HookData >> reversedHooks = new ArrayList <>(hookDataPairs );
88
125
Collections .reverse (reversedHooks );
89
126
EvaluationContext context = hookCtx .getCtx ();
90
- for (Hook hook : reversedHooks ) {
91
- if (hook .supportsFlagValueType (flagValueType )) {
92
- Optional <EvaluationContext > optional =
93
- Optional .ofNullable (hook .before (hookCtx , hints )).orElse (Optional .empty ());
94
- if (optional .isPresent ()) {
95
- context = context .merge (optional .get ());
96
- }
127
+
128
+ for (Pair <Hook , HookData > hookDataPair : reversedHooks ) {
129
+ Hook hook = hookDataPair .getLeft ();
130
+ HookData hookData = hookDataPair .getRight ();
131
+
132
+ // Create a new context with this hook's data
133
+ HookContext contextWithHookData = new HookContextWithData (hookCtx , hookData );
134
+ Optional <EvaluationContext > optional =
135
+ Optional .ofNullable (hook .before (contextWithHookData , hints )).orElse (Optional .empty ());
136
+ if (optional .isPresent ()) {
137
+ context = context .merge (optional .get ());
97
138
}
98
139
}
99
140
return context ;
0 commit comments