66import java .util .List ;
77import java .util .Map ;
88import java .util .Optional ;
9+ import java .util .function .BiConsumer ;
910import java .util .function .Consumer ;
1011import lombok .RequiredArgsConstructor ;
1112import lombok .extern .slf4j .Slf4j ;
13+ import org .apache .commons .lang3 .tuple .Pair ;
1214
1315@ Slf4j
1416@ RequiredArgsConstructor
1517@ SuppressWarnings ({"unchecked" , "rawtypes" })
1618class HookSupport {
1719
1820 public EvaluationContext beforeHooks (
19- FlagValueType flagValueType , HookContext hookCtx , List <Hook > hooks , Map <String , Object > hints ) {
20- return callBeforeHooks (flagValueType , hookCtx , hooks , hints );
21+ FlagValueType flagValueType , HookContext hookCtx , List <Pair < Hook , HookData >> hookDataPairs , Map <String , Object > hints ) {
22+ return callBeforeHooks (flagValueType , hookCtx , hookDataPairs , hints );
2123 }
2224
2325 public void afterHooks (
2426 FlagValueType flagValueType ,
2527 HookContext hookContext ,
2628 FlagEvaluationDetails details ,
27- List <Hook > hooks ,
29+ List <Pair < Hook , HookData >> hookDataPairs ,
2830 Map <String , Object > hints ) {
29- executeHooksUnchecked (flagValueType , hooks , hook -> hook .after (hookContext , details , hints ));
31+ executeHooksUnchecked (flagValueType , hookDataPairs , hookContext , ( hook , ctx ) -> hook .after (ctx , details , hints ));
3032 }
3133
3234 public void afterAllHooks (
3335 FlagValueType flagValueType ,
3436 HookContext hookCtx ,
3537 FlagEvaluationDetails details ,
36- List <Hook > hooks ,
38+ List <Pair < Hook , HookData >> hookDataPairs ,
3739 Map <String , Object > hints ) {
38- executeHooks (flagValueType , hooks , "finally" , hook -> hook .finallyAfter (hookCtx , details , hints ));
40+ executeHooks (flagValueType , hookDataPairs , hookCtx , "finally" , ( hook , ctx ) -> hook .finallyAfter (ctx , details , hints ));
3941 }
4042
4143 public void errorHooks (
4244 FlagValueType flagValueType ,
4345 HookContext hookCtx ,
4446 Exception e ,
45- List <Hook > hooks ,
47+ List <Pair < Hook , HookData >> hookDataPairs ,
4648 Map <String , Object > hints ) {
47- executeHooks (flagValueType , hooks , "error" , hook -> hook .error (hookCtx , e , hints ));
49+ executeHooks (flagValueType , hookDataPairs , hookCtx , "error" , (hook , ctx ) -> hook .error (ctx , e , hints ));
50+ }
51+
52+ public List <Pair <Hook , HookData >> getHookDataPairs (List <Hook > hooks ) {
53+ var pairs = new ArrayList <Pair <Hook , HookData >>();
54+ for (Hook hook : hooks ) {
55+ pairs .add (Pair .of (hook , HookData .create ()));
56+ }
57+ return pairs ;
4858 }
4959
5060 private <T > void executeHooks (
51- FlagValueType flagValueType , List <Hook > hooks , String hookMethod , Consumer <Hook <T >> hookCode ) {
52- if (hooks != null ) {
53- for (Hook hook : hooks ) {
61+ FlagValueType flagValueType , List <Pair <Hook , HookData >> hookDataPairs , HookContext hookContext , String hookMethod , BiConsumer <Hook <T >, HookContext > hookCode ) {
62+ if (hookDataPairs != null ) {
63+ for (Pair <Hook , HookData > hookDataPair : hookDataPairs ) {
64+ Hook hook = hookDataPair .getLeft ();
65+ HookData hookData = hookDataPair .getRight ();
5466 if (hook .supportsFlagValueType (flagValueType )) {
55- executeChecked (hook , hookCode , hookMethod );
67+ executeChecked (hook , hookData , hookContext , hookCode , hookMethod );
5668 }
5769 }
5870 }
5971 }
6072
6173 // before, error, and finally hooks shouldn't throw
62- private <T > void executeChecked (Hook <T > hook , Consumer <Hook <T >> hookCode , String hookMethod ) {
74+ private <T > void executeChecked (Hook <T > hook , HookData hookData , HookContext hookContext , BiConsumer <Hook <T >, HookContext > hookCode , String hookMethod ) {
6375 try {
64- hookCode .accept (hook );
76+ var hookCtxWithData = hookContext .withHookData (hookData );
77+ hookCode .accept (hook , hookCtxWithData );
6578 } catch (Exception exception ) {
6679 log .error (
6780 "Unhandled exception when running {} hook {} (only 'after' hooks should throw)" ,
@@ -72,35 +85,42 @@ private <T> void executeChecked(Hook<T> hook, Consumer<Hook<T>> hookCode, String
7285 }
7386
7487 // after hooks can throw in order to do validation
75- private <T > void executeHooksUnchecked (FlagValueType flagValueType , List <Hook > hooks , Consumer <Hook <T >> hookCode ) {
76- if (hooks != null ) {
77- for (Hook hook : hooks ) {
88+ private <T > void executeHooksUnchecked (FlagValueType flagValueType , List <Pair <Hook , HookData >> hookDataPairs , HookContext hookContext , BiConsumer <Hook <T >, HookContext > hookCode ) {
89+ if (hookDataPairs != null ) {
90+ for (Pair <Hook , HookData > hookDataPair : hookDataPairs ) {
91+ Hook hook = hookDataPair .getLeft ();
92+ HookData hookData = hookDataPair .getRight ();
7893 if (hook .supportsFlagValueType (flagValueType )) {
79- hookCode .accept (hook );
94+ var hookCtxWithData = hookContext .withHookData (hookData );
95+ hookCode .accept (hook , hookCtxWithData );
8096 }
8197 }
8298 }
8399 }
84100
85101 private EvaluationContext callBeforeHooks (
86- FlagValueType flagValueType , HookContext hookCtx , List <Hook > hooks , Map <String , Object > hints ) {
102+ FlagValueType flagValueType , HookContext hookCtx , List <Pair < Hook , HookData >> hookDataPairs , Map <String , Object > hints ) {
87103 // These traverse backwards from normal.
88- List <Hook > reversedHooks = new ArrayList <>(hooks );
104+ List <Pair < Hook , HookData >> reversedHooks = new ArrayList <>(hookDataPairs );
89105 Collections .reverse (reversedHooks );
90106 EvaluationContext context = hookCtx .getCtx ();
91-
107+ /*
92108 // Create hook data for each hook instance
93109 Map<Hook, HookData> hookDataMap = new HashMap<>();
94110 for (Hook hook : reversedHooks) {
95111 if (hook.supportsFlagValueType(flagValueType)) {
96112 hookDataMap.put(hook, HookData.create());
97113 }
98114 }
115+ */
116+
117+ for (Pair <Hook , HookData > hookDataPair : reversedHooks ) {
118+ Hook hook = hookDataPair .getLeft ();
119+ HookData hookData = hookDataPair .getRight ();
99120
100- for (Hook hook : reversedHooks ) {
101121 if (hook .supportsFlagValueType (flagValueType )) {
102122 // Create a new context with this hook's data
103- HookContext contextWithHookData = hookCtx .withHookData (hookDataMap . get ( hook ) );
123+ HookContext contextWithHookData = hookCtx .withHookData (hookData );
104124 Optional <EvaluationContext > optional = Optional .ofNullable (hook .before (contextWithHookData , hints ))
105125 .orElse (Optional .empty ());
106126 if (optional .isPresent ()) {
0 commit comments