1515 */
1616package com .optimizely .ab .optimizelydecision ;
1717
18- import com .optimizely .ab .OptimizelyUserContext ;
18+ import java .util .Collections ;
19+ import java .util .List ;
20+ import java .util .Map ;
21+
22+ import javax .annotation .Nonnull ;
23+
1924import org .slf4j .Logger ;
2025import org .slf4j .LoggerFactory ;
2126
22- import javax .annotation .Nonnull ;
23- import java .util .List ;
27+ import com .optimizely .ab .OptimizelyUserContext ;
2428
2529/**
26- * AsyncDecisionFetcher handles asynchronous decision fetching for a single flag key .
30+ * AsyncDecisionFetcher handles asynchronous decision fetching for single or multiple flag keys .
2731 * This class follows the same pattern as ODP's async segment fetching.
2832 */
2933public class AsyncDecisionFetcher extends Thread {
3034 private static final Logger logger = LoggerFactory .getLogger (AsyncDecisionFetcher .class );
3135
32- private final String key ;
36+ private final String singleKey ;
37+ private final List <String > keys ;
3338 private final List <OptimizelyDecideOption > options ;
34- private final OptimizelyDecisionCallback callback ;
39+ private final OptimizelyDecisionCallback singleCallback ;
40+ private final OptimizelyDecisionsCallback multipleCallback ;
3541 private final OptimizelyUserContext userContext ;
42+ private final boolean decideAll ;
43+ private final FetchType fetchType ;
44+
45+ private enum FetchType {
46+ SINGLE_DECISION ,
47+ MULTIPLE_DECISIONS ,
48+ ALL_DECISIONS
49+ }
3650
3751 /**
38- * Constructor for async decision fetching.
52+ * Constructor for async single decision fetching.
3953 *
4054 * @param userContext The user context to make decisions for
4155 * @param key The flag key to decide on
@@ -47,27 +61,112 @@ public AsyncDecisionFetcher(@Nonnull OptimizelyUserContext userContext,
4761 @ Nonnull List <OptimizelyDecideOption > options ,
4862 @ Nonnull OptimizelyDecisionCallback callback ) {
4963 this .userContext = userContext ;
50- this .key = key ;
64+ this .singleKey = key ;
65+ this .keys = null ;
5166 this .options = options ;
52- this .callback = callback ;
67+ this .singleCallback = callback ;
68+ this .multipleCallback = null ;
69+ this .decideAll = false ;
70+ this .fetchType = FetchType .SINGLE_DECISION ;
5371
54- // Set thread name for debugging
5572 setName ("AsyncDecisionFetcher-" + key );
73+ setDaemon (true );
74+ }
75+
76+ /**
77+ * Constructor for deciding on specific keys.
78+ *
79+ * @param userContext The user context to make decisions for
80+ * @param keys List of flag keys to decide on
81+ * @param options Decision options
82+ * @param callback Callback to invoke when decisions are ready
83+ */
84+ public AsyncDecisionFetcher (@ Nonnull OptimizelyUserContext userContext ,
85+ @ Nonnull List <String > keys ,
86+ @ Nonnull List <OptimizelyDecideOption > options ,
87+ @ Nonnull OptimizelyDecisionsCallback callback ) {
88+ this .userContext = userContext ;
89+ this .singleKey = null ;
90+ this .keys = keys ;
91+ this .options = options ;
92+ this .singleCallback = null ;
93+ this .multipleCallback = callback ;
94+ this .decideAll = false ;
95+ this .fetchType = FetchType .MULTIPLE_DECISIONS ;
5696
57- // Set as daemon thread so it doesn't prevent JVM shutdown
97+ setName ("AsyncDecisionFetcher-keys" );
98+ setDaemon (true );
99+ }
100+
101+ /**
102+ * Constructor for deciding on all flags.
103+ *
104+ * @param userContext The user context to make decisions for
105+ * @param options Decision options
106+ * @param callback Callback to invoke when decisions are ready
107+ */
108+ public AsyncDecisionFetcher (@ Nonnull OptimizelyUserContext userContext ,
109+ @ Nonnull List <OptimizelyDecideOption > options ,
110+ @ Nonnull OptimizelyDecisionsCallback callback ) {
111+ this .userContext = userContext ;
112+ this .singleKey = null ;
113+ this .keys = null ;
114+ this .options = options ;
115+ this .singleCallback = null ;
116+ this .multipleCallback = callback ;
117+ this .decideAll = true ;
118+ this .fetchType = FetchType .ALL_DECISIONS ;
119+
120+ setName ("AsyncDecisionFetcher-all" );
58121 setDaemon (true );
59122 }
60123
61124 @ Override
62125 public void run () {
63126 try {
64- OptimizelyDecision decision = userContext .decide (key , options );
65- callback .onCompleted (decision );
127+ switch (fetchType ) {
128+ case SINGLE_DECISION :
129+ handleSingleDecision ();
130+ break ;
131+ case MULTIPLE_DECISIONS :
132+ handleMultipleDecisions ();
133+ break ;
134+ case ALL_DECISIONS :
135+ handleAllDecisions ();
136+ break ;
137+ }
66138 } catch (Exception e ) {
67- logger .error ("Error in async decision fetching for key: " + key , e );
68- // Create an error decision and pass it to the callback
69- OptimizelyDecision errorDecision = createErrorDecision (key , e .getMessage ());
70- callback .onCompleted (errorDecision );
139+ logger .error ("Error in async decision fetching" , e );
140+ handleError (e );
141+ }
142+ }
143+
144+ private void handleSingleDecision () {
145+ OptimizelyDecision decision = userContext .decide (singleKey , options );
146+ singleCallback .onCompleted (decision );
147+ }
148+
149+ private void handleMultipleDecisions () {
150+ Map <String , OptimizelyDecision > decisions = userContext .decideForKeys (keys , options );
151+ multipleCallback .onCompleted (decisions );
152+ }
153+
154+ private void handleAllDecisions () {
155+ Map <String , OptimizelyDecision > decisions = userContext .decideAll (options );
156+ multipleCallback .onCompleted (decisions );
157+ }
158+
159+ private void handleError (Exception e ) {
160+ switch (fetchType ) {
161+ case SINGLE_DECISION :
162+ OptimizelyDecision errorDecision = createErrorDecision (singleKey , e .getMessage ());
163+ singleCallback .onCompleted (errorDecision );
164+ break ;
165+ case MULTIPLE_DECISIONS :
166+ case ALL_DECISIONS :
167+ // Return empty map on error - this follows the pattern of sync methods
168+ multipleCallback .onCompleted (Collections .emptyMap ());
169+ break ;
71170 }
72171 }
73172
0 commit comments