22
33import com .google .common .annotations .VisibleForTesting ;
44
5+ import io .split .Spec ;
56import io .split .client .dtos .SplitChange ;
67import io .split .client .dtos .SplitHttpResponse ;
8+ import io .split .client .dtos .RuleBasedSegment ;
9+ import io .split .client .dtos .SplitChangesOldPayloadDto ;
10+ import io .split .client .dtos .ChangeDto ;
11+ import io .split .client .dtos .Split ;
712import io .split .client .exceptions .UriTooLongException ;
813import io .split .client .utils .Json ;
914import io .split .client .utils .Utils ;
2025
2126import java .net .URI ;
2227import java .net .URISyntaxException ;
28+ import java .util .ArrayList ;
2329
2430import static com .google .common .base .Preconditions .checkNotNull ;
2531import static io .split .Spec .SPEC_1_3 ;
32+ import static io .split .Spec .SPEC_1_1 ;
2633
2734/**
2835 * Created by adilaijaz on 5/30/15.
2936 */
3037public final class HttpSplitChangeFetcher implements SplitChangeFetcher {
3138 private static final Logger _log = LoggerFactory .getLogger (HttpSplitChangeFetcher .class );
3239
40+ private final Object _lock = new Object ();
3341 private static final String SINCE = "since" ;
3442 private static final String RB_SINCE = "rbSince" ;
3543 private static final String TILL = "till" ;
3644 private static final String SETS = "sets" ;
3745 private static final String SPEC = "s" ;
3846 private String specVersion = SPEC_1_3 ;
47+ private int PROXY_CHECK_INTERVAL_MILLISECONDS_SS = 24 * 60 * 60 * 1000 ;
48+ private Long _lastProxyCheckTimestamp = 0L ;
3949 private final SplitHttpClient _client ;
4050 private final URI _target ;
4151 private final TelemetryRuntimeProducer _telemetryRuntimeProducer ;
52+ private final boolean _rootURIOverriden ;
4253
43- public static HttpSplitChangeFetcher create (SplitHttpClient client , URI root , TelemetryRuntimeProducer telemetryRuntimeProducer )
54+ public static HttpSplitChangeFetcher create (SplitHttpClient client , URI root , TelemetryRuntimeProducer telemetryRuntimeProducer ,
55+ boolean rootURIOverriden )
4456 throws URISyntaxException {
45- return new HttpSplitChangeFetcher (client , Utils .appendPath (root , "api/splitChanges" ), telemetryRuntimeProducer );
57+ return new HttpSplitChangeFetcher (client , Utils .appendPath (root , "api/splitChanges" ), telemetryRuntimeProducer , rootURIOverriden );
4658 }
4759
48- private HttpSplitChangeFetcher (SplitHttpClient client , URI uri , TelemetryRuntimeProducer telemetryRuntimeProducer ) {
60+ private HttpSplitChangeFetcher (SplitHttpClient client , URI uri , TelemetryRuntimeProducer telemetryRuntimeProducer , boolean rootURIOverriden ) {
4961 _client = client ;
5062 _target = uri ;
5163 checkNotNull (_target );
5264 _telemetryRuntimeProducer = checkNotNull (telemetryRuntimeProducer );
65+ _rootURIOverriden = rootURIOverriden ;
5366 }
5467
5568 long makeRandomTill () {
@@ -61,32 +74,63 @@ long makeRandomTill() {
6174 public SplitChange fetch (long since , long sinceRBS , FetchOptions options ) {
6275 long start = System .currentTimeMillis ();
6376 try {
77+ if (specVersion .equals (SPEC_1_1 ) && (System .currentTimeMillis () - _lastProxyCheckTimestamp >= PROXY_CHECK_INTERVAL_MILLISECONDS_SS )) {
78+ _log .info ("Switching to new Feature flag spec ({}) and fetching." , SPEC_1_3 );
79+ specVersion = SPEC_1_3 ;
80+ }
6481 URI uri = buildURL (options , since , sinceRBS );
6582 SplitHttpResponse response = _client .get (uri , options , null );
66-
6783 if (response .statusCode () < HttpStatus .SC_OK || response .statusCode () >= HttpStatus .SC_MULTIPLE_CHOICES ) {
6884 if (response .statusCode () == HttpStatus .SC_REQUEST_URI_TOO_LONG ) {
6985 _log .error ("The amount of flag sets provided are big causing uri length error." );
7086 throw new UriTooLongException (String .format ("Status code: %s. Message: %s" , response .statusCode (), response .statusMessage ()));
7187 }
7288
89+ if (response .statusCode () == HttpStatus .SC_BAD_REQUEST && specVersion .equals (Spec .SPEC_1_3 ) && _rootURIOverriden ) {
90+ specVersion = Spec .SPEC_1_1 ;
91+ _log .warn ("Detected proxy without support for Feature flags spec {} version, will switch to spec version {}" ,
92+ SPEC_1_3 , SPEC_1_1 );
93+ _lastProxyCheckTimestamp = System .currentTimeMillis ();
94+ return fetch (since , 0 , options );
95+ }
96+
7397 _telemetryRuntimeProducer .recordSyncError (ResourceEnum .SPLIT_SYNC , response .statusCode ());
7498 throw new IllegalStateException (
7599 String .format ("Could not retrieve splitChanges since %s; http return code %s" , since , response .statusCode ())
76100 );
77101 }
78- return Json .fromJson (response .body (), SplitChange .class );
102+
103+ String body = response .body ();
104+ if (specVersion .equals (Spec .SPEC_1_1 )) {
105+ return Json .fromJson (body , SplitChangesOldPayloadDto .class ).toSplitChange ();
106+ }
107+
108+ return Json .fromJson (body , SplitChange .class );
109+
79110 } catch (Exception e ) {
80111 throw new IllegalStateException (String .format ("Problem fetching splitChanges since %s: %s" , since , e ), e );
81112 } finally {
82113 _telemetryRuntimeProducer .recordSyncLatency (HTTPLatenciesEnum .SPLITS , System .currentTimeMillis () - start );
83114 }
84115 }
85116
117+ public Long getLastProxyCheckTimestamp () {
118+ return _lastProxyCheckTimestamp ;
119+ }
120+
121+ public void setLastProxyCheckTimestamp (long lastProxyCheckTimestamp ) {
122+ synchronized (_lock ) {
123+ _lastProxyCheckTimestamp = lastProxyCheckTimestamp ;
124+ }
125+ }
126+
127+
86128 private URI buildURL (FetchOptions options , long since , long sinceRBS ) throws URISyntaxException {
87129 URIBuilder uriBuilder = new URIBuilder (_target ).addParameter (SPEC , "" + specVersion );
88130 uriBuilder .addParameter (SINCE , "" + since );
89- uriBuilder .addParameter (RB_SINCE , "" + sinceRBS );
131+ if (specVersion .equals (SPEC_1_3 )) {
132+ uriBuilder .addParameter (RB_SINCE , "" + sinceRBS );
133+ }
90134 if (!options .flagSetsFilter ().isEmpty ()) {
91135 uriBuilder .addParameter (SETS , "" + options .flagSetsFilter ());
92136 }
0 commit comments