11package com .datadog .featureflag ;
22
3- import com .squareup .moshi .JsonAdapter ;
4- import com .squareup .moshi .JsonDataException ;
5- import com .squareup .moshi .JsonReader ;
6- import com .squareup .moshi .JsonWriter ;
7- import com .squareup .moshi .Moshi ;
8- import com .squareup .moshi .Types ;
93import datadog .communication .ddagent .SharedCommunicationObjects ;
104import datadog .remoteconfig .Capabilities ;
115import datadog .remoteconfig .ConfigurationChangesTypedListener ;
12- import datadog .remoteconfig .ConfigurationDeserializer ;
136import datadog .remoteconfig .ConfigurationPoller ;
147import datadog .remoteconfig .PollingRateHinter ;
158import datadog .remoteconfig .Product ;
169import datadog .trace .api .Config ;
1710import datadog .trace .api .featureflag .FeatureFlaggingGateway ;
18- import datadog .trace .api .featureflag .ufc .v1 .Flag ;
1911import datadog .trace .api .featureflag .ufc .v1 .ServerConfiguration ;
20- import java .io .ByteArrayInputStream ;
21- import java .io .IOException ;
22- import java .lang .annotation .Annotation ;
23- import java .lang .reflect .Type ;
24- import java .time .Instant ;
25- import java .time .format .DateTimeFormatter ;
26- import java .util .Date ;
27- import java .util .HashMap ;
28- import java .util .Map ;
29- import java .util .Set ;
30- import javax .annotation .Nonnull ;
3112import javax .annotation .Nullable ;
32- import okio .Okio ;
3313
3414public class RemoteConfigServiceImpl
3515 implements ConfigurationSourceService , ConfigurationChangesTypedListener <ServerConfiguration > {
@@ -43,8 +23,7 @@ public RemoteConfigServiceImpl(final SharedCommunicationObjects sco, final Confi
4323 @ Override
4424 public void init () {
4525 configurationPoller .addCapabilities (Capabilities .CAPABILITY_FFE_FLAG_CONFIGURATION_RULES );
46- configurationPoller .addListener (
47- Product .FFE_FLAGS , UniversalFlagConfigDeserializer .INSTANCE , this );
26+ configurationPoller .addListener (Product .FFE_FLAGS , UniversalFlagConfigParser .INSTANCE , this );
4827 configurationPoller .start ();
4928 }
5029
@@ -62,131 +41,4 @@ public void accept(
6241 final PollingRateHinter pollingRateHinter ) {
6342 FeatureFlaggingGateway .dispatch (configuration );
6443 }
65-
66- static class UniversalFlagConfigDeserializer
67- implements ConfigurationDeserializer <ServerConfiguration > {
68-
69- private static final String UNIVERSAL_FLAG_CONFIGURATION_TYPE = "universal-flag-configuration" ;
70- static final UniversalFlagConfigDeserializer INSTANCE = new UniversalFlagConfigDeserializer ();
71-
72- private static final Moshi MOSHI =
73- new Moshi .Builder ().add (Date .class , new DateAdapter ()).add (FlagMapAdapter .FACTORY ).build ();
74- private static final JsonAdapter <ServerConfiguration > V1_ADAPTER =
75- MOSHI .adapter (ServerConfiguration .class );
76- private static final Type API_RESPONSE_TYPE =
77- Types .newParameterizedType (Map .class , String .class , Object .class );
78- private static final JsonAdapter <Map <String , Object >> API_RESPONSE_ADAPTER =
79- MOSHI .adapter (API_RESPONSE_TYPE );
80-
81- @ Override
82- public ServerConfiguration deserialize (final byte [] content ) throws IOException {
83- return V1_ADAPTER .fromJson (Okio .buffer (Okio .source (new ByteArrayInputStream (content ))));
84- }
85-
86- @ Nullable
87- ServerConfiguration deserializeApiResponse (final byte [] content ) throws IOException {
88- final Map <String , Object > response =
89- API_RESPONSE_ADAPTER .fromJson (
90- Okio .buffer (Okio .source (new ByteArrayInputStream (content ))));
91- if (response != null && response .containsKey ("data" )) {
92- final Object data = response .get ("data" );
93- if (!(data instanceof Map )) {
94- return null ;
95- }
96- final Map <?, ?> dataAttributes = (Map <?, ?>) data ;
97- return UNIVERSAL_FLAG_CONFIGURATION_TYPE .equals (dataAttributes .get ("type" ))
98- ? validConfiguration (V1_ADAPTER .fromJsonValue (dataAttributes .get ("attributes" )))
99- : null ;
100- }
101- return null ;
102- }
103-
104- @ Nullable
105- private static ServerConfiguration validConfiguration (
106- @ Nullable final ServerConfiguration configuration ) {
107- return configuration != null && configuration .flags != null ? configuration : null ;
108- }
109- }
110-
111- static class FlagMapAdapter extends JsonAdapter <Map <String , Flag >> {
112-
113- private static final Type FLAGS_TYPE =
114- Types .newParameterizedType (Map .class , String .class , Flag .class );
115-
116- static final Factory FACTORY =
117- new Factory () {
118- @ Nullable
119- @ Override
120- public JsonAdapter <?> create (
121- @ Nonnull final Type type ,
122- @ Nonnull final Set <? extends Annotation > annotations ,
123- @ Nonnull final Moshi moshi ) {
124- if (!annotations .isEmpty () || !Types .equals (type , FLAGS_TYPE )) {
125- return null ;
126- }
127- return new FlagMapAdapter (moshi .adapter (Flag .class ));
128- }
129- };
130-
131- private final JsonAdapter <Flag > flagAdapter ;
132-
133- FlagMapAdapter (final JsonAdapter <Flag > flagAdapter ) {
134- this .flagAdapter = flagAdapter ;
135- }
136-
137- @ Nullable
138- @ Override
139- public Map <String , Flag > fromJson (@ Nonnull final JsonReader reader ) throws IOException {
140- if (reader .peek () == JsonReader .Token .NULL ) {
141- return reader .nextNull ();
142- }
143- final Map <String , Flag > flags = new HashMap <>();
144- reader .beginObject ();
145- while (reader .hasNext ()) {
146- final String flagKey = reader .nextName ();
147- final Object rawFlag = reader .readJsonValue ();
148- try {
149- final Flag flag = flagAdapter .fromJsonValue (rawFlag );
150- if (flag != null ) {
151- flags .put (flagKey , flag );
152- }
153- } catch (JsonDataException | IllegalArgumentException ignored ) {
154- // A malformed flag must not prevent other flags in the same config from evaluating.
155- }
156- }
157- reader .endObject ();
158- return flags ;
159- }
160-
161- @ Override
162- public void toJson (@ Nonnull final JsonWriter writer , @ Nullable final Map <String , Flag > value )
163- throws IOException {
164- throw new UnsupportedOperationException ("Reading only adapter" );
165- }
166- }
167-
168- static class DateAdapter extends JsonAdapter <Date > {
169-
170- @ Nullable
171- @ Override
172- public Date fromJson (@ Nonnull final JsonReader reader ) throws IOException {
173- final String date = reader .nextString ();
174- if (date == null ) {
175- return null ;
176- }
177- try {
178- final Instant instant = DateTimeFormatter .ISO_OFFSET_DATE_TIME .parse (date , Instant ::from );
179- return Date .from (instant );
180- } catch (Exception e ) {
181- // ignore wrongly set dates
182- return null ;
183- }
184- }
185-
186- @ Override
187- public void toJson (@ Nonnull final JsonWriter writer , @ Nullable final Date value )
188- throws IOException {
189- throw new UnsupportedOperationException ("Reading only adapter" );
190- }
191- }
19244}
0 commit comments