44import com .launchdarkly .sdk .internal .fdv2 .payloads .FDv2Event ;
55import com .launchdarkly .sdk .internal .fdv2 .sources .FDv2ProtocolHandler ;
66import com .launchdarkly .sdk .internal .fdv2 .sources .Selector ;
7- import com .launchdarkly .sdk .internal .http .HttpErrors ;
87import com .launchdarkly .sdk .server .datasources .FDv2SourceResult ;
98import com .launchdarkly .sdk .server .interfaces .DataSourceStatusProvider ;
109import com .launchdarkly .sdk .server .subsystems .DataStoreTypes ;
@@ -29,23 +28,28 @@ protected void internalShutdown() {
2928 requestor .close ();
3029 }
3130
31+ private static boolean getFallback (FDv2Requestor .FDv2PayloadResponse response ) {
32+ if (response != null && response .getHeaders () != null ) {
33+ String headerValue = response .getHeaders ().get (HeaderConstants .FDV1_FALLBACK .getHeaderName ());
34+ return headerValue != null && headerValue .equalsIgnoreCase ("true" );
35+ }
36+
37+ return false ;
38+ }
39+
40+ private static String getEnvironmentId (FDv2Requestor .FDv2PayloadResponse response ) {
41+ if (response != null && response .getHeaders () != null ) {
42+ return response .getHeaders ().get (HeaderConstants .ENVIRONMENT_ID .getHeaderName ());
43+ }
44+ return null ;
45+ }
46+
3247 protected CompletableFuture <FDv2SourceResult > poll (Selector selector , boolean oneShot ) {
3348 return requestor .Poll (selector ).handle (((pollingResponse , ex ) -> {
49+ boolean fdv1Fallback = getFallback (pollingResponse );
50+ String environmentId = getEnvironmentId (pollingResponse );
3451 if (ex != null ) {
35- if (ex instanceof HttpErrors .HttpErrorException ) {
36- HttpErrors .HttpErrorException e = (HttpErrors .HttpErrorException ) ex ;
37- DataSourceStatusProvider .ErrorInfo errorInfo = DataSourceStatusProvider .ErrorInfo .fromHttpError (e .getStatus ());
38- // Errors without an HTTP status are recoverable. If there is a status, then we check if the error
39- // is recoverable.
40- boolean recoverable = e .getStatus () <= 0 || isHttpErrorRecoverable (e .getStatus ());
41- logger .error ("Polling request failed with HTTP error: {}" , e .getStatus ());
42- // For a one-shot request all errors are terminal.
43- if (oneShot ) {
44- return FDv2SourceResult .terminalError (errorInfo );
45- } else {
46- return recoverable ? FDv2SourceResult .interrupted (errorInfo ) : FDv2SourceResult .terminalError (errorInfo );
47- }
48- } else if (ex instanceof IOException ) {
52+ if (ex instanceof IOException ) {
4953 IOException e = (IOException ) ex ;
5054 logger .error ("Polling request failed with network error: {}" , e .toString ());
5155 DataSourceStatusProvider .ErrorInfo info = new DataSourceStatusProvider .ErrorInfo (
@@ -54,7 +58,7 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
5458 e .toString (),
5559 new Date ().toInstant ()
5660 );
57- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
61+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
5862 } else if (ex instanceof SerializationException ) {
5963 SerializationException e = (SerializationException ) ex ;
6064 logger .error ("Polling request received malformed data: {}" , e .toString ());
@@ -64,7 +68,7 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
6468 e .toString (),
6569 new Date ().toInstant ()
6670 );
67- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
71+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
6872 }
6973 String msg = ex .toString ();
7074 logger .error ("Polling request failed with an unknown error: {}" , msg );
@@ -74,17 +78,30 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
7478 msg ,
7579 new Date ().toInstant ()
7680 );
77- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
81+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
7882 }
79- // A null polling response indicates that we received a 304, which means nothing has changed.
80- if (pollingResponse == null ) {
83+ // If we get a 304, then that means nothing has changed.
84+ if (pollingResponse . getStatusCode () == 304 ) {
8185 return FDv2SourceResult .changeSet (
8286 new DataStoreTypes .ChangeSet <>(DataStoreTypes .ChangeSetType .None ,
8387 Selector .EMPTY ,
8488 null ,
85- // TODO: Implement environment ID support.
86- null
87- ));
89+ null // Header derived values will have been handled on initial response.
90+ ),
91+ // Headers would have been processed from the initial response.
92+ false );
93+ }
94+ if (!pollingResponse .isSuccess ()) {
95+ int statusCode = pollingResponse .getStatusCode ();
96+ boolean recoverable = statusCode <= 0 || isHttpErrorRecoverable (statusCode );
97+ DataSourceStatusProvider .ErrorInfo errorInfo = DataSourceStatusProvider .ErrorInfo .fromHttpError (statusCode );
98+ logger .error ("Polling request failed with HTTP error: {}" , statusCode );
99+ // For a one-shot request all errors are terminal.
100+ if (oneShot ) {
101+ return FDv2SourceResult .terminalError (errorInfo , fdv1Fallback );
102+ } else {
103+ return recoverable ? FDv2SourceResult .interrupted (errorInfo , fdv1Fallback ) : FDv2SourceResult .terminalError (errorInfo , fdv1Fallback );
104+ }
88105 }
89106 FDv2ProtocolHandler handler = new FDv2ProtocolHandler ();
90107 for (FDv2Event event : pollingResponse .getEvents ()) {
@@ -96,10 +113,9 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
96113 DataStoreTypes .ChangeSet <DataStoreTypes .ItemDescriptor > converted = FDv2ChangeSetTranslator .toChangeSet (
97114 ((FDv2ProtocolHandler .FDv2ActionChangeset ) res ).getChangeset (),
98115 logger ,
99- // TODO: Implement environment ID support.
100- null
116+ environmentId
101117 );
102- return FDv2SourceResult .changeSet (converted );
118+ return FDv2SourceResult .changeSet (converted , fdv1Fallback );
103119 } catch (Exception e ) {
104120 // TODO: Do we need to be more specific about the exception type here?
105121 DataSourceStatusProvider .ErrorInfo info = new DataSourceStatusProvider .ErrorInfo (
@@ -108,7 +124,7 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
108124 e .toString (),
109125 new Date ().toInstant ()
110126 );
111- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
127+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
112128 }
113129 case ERROR : {
114130 FDv2ProtocolHandler .FDv2ActionError error = ((FDv2ProtocolHandler .FDv2ActionError ) res );
@@ -117,10 +133,10 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
117133 0 ,
118134 error .getReason (),
119135 new Date ().toInstant ());
120- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
136+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
121137 }
122138 case GOODBYE :
123- return FDv2SourceResult .goodbye (((FDv2ProtocolHandler .FDv2ActionGoodbye ) res ).getReason ());
139+ return FDv2SourceResult .goodbye (((FDv2ProtocolHandler .FDv2ActionGoodbye ) res ).getReason (), fdv1Fallback );
124140 case NONE :
125141 break ;
126142 case INTERNAL_ERROR : {
@@ -141,7 +157,7 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
141157 0 ,
142158 "Internal error occurred during polling" ,
143159 new Date ().toInstant ());
144- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
160+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
145161 }
146162 }
147163 }
@@ -152,7 +168,7 @@ protected CompletableFuture<FDv2SourceResult> poll(Selector selector, boolean on
152168 "Unexpected end of polling response" ,
153169 new Date ().toInstant ()
154170 );
155- return oneShot ? FDv2SourceResult .terminalError (info ) : FDv2SourceResult .interrupted (info );
171+ return oneShot ? FDv2SourceResult .terminalError (info , fdv1Fallback ) : FDv2SourceResult .interrupted (info , fdv1Fallback );
156172 }));
157173 }
158174}
0 commit comments