Skip to content

Commit

Permalink
[AppConfig] Make sure the consistency behaviors between languages. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mssfang authored Jul 6, 2021
1 parent c3b1ee9 commit 9f0aa26
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ public final class ConfigurationSettingJsonDeserializer extends JsonDeserializer
configurationSettingSubclassDeserializer(FeatureFlagConfigurationSetting.class));
}

/**
* Gets a module wrapping this deserializer as an adapter for the Jackson
* ObjectMapper.
*
* @return a simple module to be plugged onto Jackson ObjectMapper.
*/
public static SimpleModule getModule() {
return MODULE;
}
Expand Down Expand Up @@ -113,17 +119,8 @@ private static SecretReferenceConfigurationSetting readSecretReferenceConfigurat
settingValue = valueNode.asText();
}

final JsonNode settingValueNode = toJsonNode(settingValue);

final JsonNode uriNode = settingValueNode.get(URI);
String secretID = null;
if (uriNode != null && !uriNode.isNull()) {
secretID = uriNode.asText(); // uri node contains the secret ID value
}

SecretReferenceConfigurationSetting secretReferenceConfigurationSetting =
new SecretReferenceConfigurationSetting(secretID, secretID)
.setKey(baseSetting.getKey())
readSecretReferenceConfigurationSettingValue(baseSetting.getKey(), settingValue)
.setValue(settingValue)
.setLabel(baseSetting.getLabel())
.setETag(baseSetting.getETag())
Expand Down Expand Up @@ -199,7 +196,34 @@ private static <T extends ConfigurationSetting> ConfigurationSetting configurati
return setting;
}

private static FeatureFlagConfigurationSetting readFeatureFlagConfigurationSettingValue(String settingValue) {
/**
* Given a JSON format string {@code settingValue}, deserializes it into a {@link JsonNode} and returns a
* {@link SecretReferenceConfigurationSetting} object.
*
* @param key the {@code key} property of setting.
* @param settingValue a JSON format string that represents the {@code value} property of setting.
* @return A {@link SecretReferenceConfigurationSetting} object.
*/
public static SecretReferenceConfigurationSetting readSecretReferenceConfigurationSettingValue(String key,
String settingValue) {
final JsonNode settingValueNode = toJsonNode(settingValue);

final JsonNode uriNode = settingValueNode.get(URI);
String secretID = null;
if (uriNode != null && !uriNode.isNull()) {
secretID = uriNode.asText(); // uri node contains the secret ID value
}
return new SecretReferenceConfigurationSetting(key, secretID);
}

/**
* Given a JSON format string {@code settingValue}, deserializes it into a {@link JsonNode} and returns a
* {@link FeatureFlagConfigurationSetting} object.
*
* @param settingValue a JSON format string that represents the {@code value} property of setting.
* @return A {@link FeatureFlagConfigurationSetting} object which converted from the {@code settingValue}.
*/
public static FeatureFlagConfigurationSetting readFeatureFlagConfigurationSettingValue(String settingValue) {
JsonNode settingValueNode = toJsonNode(settingValue);

final JsonNode featureIdNode = settingValueNode.get(ID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public final class ConfigurationSettingJsonSerializer extends JsonSerializer<Con
MODULE.addSerializer(ConfigurationSetting.class, new ConfigurationSettingJsonSerializer());
}

/**
* Gets a module wrapping this serializer as an adapter for the Jackson
* ObjectMapper.
*
* @return a simple module to be plugged onto Jackson ObjectMapper.
*/
public static SimpleModule getModule() {
return MODULE;
}
Expand All @@ -63,18 +69,11 @@ public void serialize(ConfigurationSetting value, JsonGenerator gen, SerializerP

private static void write(ConfigurationSetting value, JsonGenerator gen) throws IOException {
gen.writeStartObject();
// The setting's value is expected to be a JSON string for the FeatureFlagConfigurationSetting and
// SecretReferenceConfigurationSetting, so it is better to use another JSON generator
// to constructor the value as JSON string, flush into the StringWriter.
final StringWriter jsonObjectWriter = new StringWriter();
final JsonGenerator generator = new JsonFactory().createGenerator(jsonObjectWriter);
String settingValue;
if (value instanceof FeatureFlagConfigurationSetting) {
writeFeatureFlagConfigurationSetting((FeatureFlagConfigurationSetting) value, generator);
settingValue = jsonObjectWriter.toString();
settingValue = writeFeatureFlagConfigurationSetting((FeatureFlagConfigurationSetting) value);
} else if (value instanceof SecretReferenceConfigurationSetting) {
writeSecretReferenceConfigurationSetting((SecretReferenceConfigurationSetting) value, generator);
settingValue = jsonObjectWriter.toString();
settingValue = writeSecretReferenceConfigurationSetting((SecretReferenceConfigurationSetting) value);
} else {
settingValue = value.getValue();
}
Expand All @@ -100,16 +99,43 @@ private static void write(ConfigurationSetting value, JsonGenerator gen) throws
gen.writeEndObject();
}

private static void writeSecretReferenceConfigurationSetting(SecretReferenceConfigurationSetting setting,
JsonGenerator gen) throws IOException {
/**
* Serialize the strongly-type property, {@code secretId} of {@link SecretReferenceConfigurationSetting} into a
* JSON format string, which is the {@code value} of {@link SecretReferenceConfigurationSetting}.
*
* @param setting the {@link SecretReferenceConfigurationSetting}.
* @return a JSON format string that represents the {@code value} of {@link SecretReferenceConfigurationSetting}.
* @throws IOException if {@link JsonGenerator} can not be created.
*/
public static String writeSecretReferenceConfigurationSetting(SecretReferenceConfigurationSetting setting)
throws IOException {
// The setting's value is expected to be a JSON string for the SecretReferenceConfigurationSetting,
// so it is better to use another JSON generator to constructor the value as JSON string, flush into the
// StringWriter.
final StringWriter jsonObjectWriter = new StringWriter();
final JsonGenerator gen = new JsonFactory().createGenerator(jsonObjectWriter);
gen.writeStartObject();
gen.writeStringField(URI, setting.getSecretId());
gen.writeEndObject();
gen.close();
return jsonObjectWriter.toString();
}

private static void writeFeatureFlagConfigurationSetting(FeatureFlagConfigurationSetting setting,
JsonGenerator gen) throws IOException {
/**
* Serialize the strong-type properties, such as {@code featureId} of {@link FeatureFlagConfigurationSetting}
* into a JSON format string, which is the {@code value} of {@link FeatureFlagConfigurationSetting}.
*
* @param setting the {@link FeatureFlagConfigurationSetting}.
* @return a JSON format string that represents the {@code value} of {@link FeatureFlagConfigurationSetting}.
* @throws IOException if {@link JsonGenerator} can not be created.
*/
public static String writeFeatureFlagConfigurationSetting(FeatureFlagConfigurationSetting setting)
throws IOException {
// The setting's value is expected to be a JSON string for the FeatureFlagConfigurationSetting,
// so it is better to use another JSON generator to constructor the value as JSON string, flush into the
// StringWriter.
final StringWriter jsonObjectWriter = new StringWriter();
final JsonGenerator gen = new JsonFactory().createGenerator(jsonObjectWriter);
gen.writeStartObject();

gen.writeStringField(ID, setting.getFeatureId());
Expand All @@ -119,19 +145,23 @@ private static void writeFeatureFlagConfigurationSetting(FeatureFlagConfiguratio

gen.writeObjectFieldStart(CONDITIONS);
gen.writeArrayFieldStart(CLIENT_FILTERS);
for (FeatureFlagFilter filter : setting.getClientFilters()) {
gen.writeStartObject();
gen.writeStringField(NAME, filter.getName());
gen.writeObjectFieldStart(PARAMETERS);
writeMapProperties(filter.getParameters(), gen);
gen.writeEndObject(); // parameters object
gen.writeEndObject(); // each filter object
if (setting.getClientFilters() != null) {
for (FeatureFlagFilter filter : setting.getClientFilters()) {
gen.writeStartObject();
gen.writeStringField(NAME, filter.getName());
gen.writeObjectFieldStart(PARAMETERS);
writeMapProperties(filter.getParameters(), gen);
gen.writeEndObject(); // parameters object
gen.writeEndObject(); // each filter object
}
}
gen.writeEndArray();
gen.writeEndObject();

gen.writeEndObject();
gen.close();

return jsonObjectWriter.toString();
}

private static void writeMapProperties(Map<String, ? extends Object> properties, JsonGenerator gen)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,31 @@

package com.azure.data.appconfiguration.models;

import java.util.Collections;
import com.azure.core.util.logging.ClientLogger;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import static com.azure.data.appconfiguration.implementation.ConfigurationSettingJsonDeserializer.readFeatureFlagConfigurationSettingValue;
import static com.azure.data.appconfiguration.implementation.ConfigurationSettingJsonSerializer.writeFeatureFlagConfigurationSetting;

/**
* {@link FeatureFlagConfigurationSetting} allows you to customize your own feature flags to dynamically administer a
* feature's lifecycle. Feature flags can be used to enable or disable features.
*/
public final class FeatureFlagConfigurationSetting extends ConfigurationSetting {
private final String featureId;
private final boolean isEnabled;
private static final ClientLogger LOGGER = new ClientLogger(FeatureFlagConfigurationSetting.class);
private static final String FEATURE_FLAG_CONTENT_TYPE = "application/vnd.microsoft.appconfig.ff+json;charset=utf-8";

private String featureId;
private boolean isEnabled;
private String description;
private String displayName;
private List<FeatureFlagFilter> clientFilters;

private static final String FEATURE_FLAG_CONTENT_TYPE = "application/vnd.microsoft.appconfig.ff+json;charset=utf-8";

/**
* A prefix is used to construct a feature flag configuration setting's key.
*/
Expand Down Expand Up @@ -58,10 +66,24 @@ public FeatureFlagConfigurationSetting setKey(String key) {
* @param value The value to associate with this configuration setting.
*
* @return The updated {@link FeatureFlagConfigurationSetting} object.
* @throws IllegalArgumentException if the setting's {@code value} is an invalid JSON format.
*/
@Override
public FeatureFlagConfigurationSetting setValue(String value) {
super.setValue(value);
// update strongly-typed properties.
final FeatureFlagConfigurationSetting updatedSetting = readFeatureFlagConfigurationSettingValue(value);
this.featureId = updatedSetting.getFeatureId();
this.description = updatedSetting.getDescription();
this.isEnabled = updatedSetting.isEnabled();
this.displayName = updatedSetting.getDisplayName();
if (updatedSetting.getClientFilters() != null) {
this.clientFilters = StreamSupport.stream(updatedSetting.getClientFilters().spliterator(), false)
.collect(Collectors.toList());
} else {
this.clientFilters = null;
}

return this;
}

Expand Down Expand Up @@ -127,6 +149,21 @@ public String getFeatureId() {
return featureId;
}

/**
* Set the feature ID of this configuration setting.
*
* @param featureId the feature ID of this configuration setting.
*
* @return The updated {@link FeatureFlagConfigurationSetting} object.
* @throws IllegalArgumentException if the setting's {@code value} is an invalid JSON format.
*/
public FeatureFlagConfigurationSetting setFeatureId(String featureId) {
this.featureId = featureId;
super.setKey(KEY_PREFIX + featureId);
updateSettingValue();
return this;
}

/**
* Get the boolean indicator to show if the setting is turn on or off.
*
Expand All @@ -136,6 +173,20 @@ public boolean isEnabled() {
return this.isEnabled;
}

/**
* Set the boolean indicator to show if the setting is turn on or off.
*
* @param isEnabled the boolean indicator to show if the setting is turn on or off.
* @return The updated {@link FeatureFlagConfigurationSetting} object.
* @throws IllegalArgumentException if the setting's {@code value} is an invalid JSON format.
*/
public FeatureFlagConfigurationSetting setEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
updateSettingValue();
return this;
}

/**
* Get the description of this configuration setting.
*
Expand All @@ -151,9 +202,11 @@ public String getDescription() {
* @param description the description of this configuration setting.
*
* @return The updated {@link FeatureFlagConfigurationSetting} object.
* @throws IllegalArgumentException if the setting's {@code value} is an invalid JSON format.
*/
public FeatureFlagConfigurationSetting setDescription(String description) {
this.description = description;
updateSettingValue();
return this;
}

Expand All @@ -172,9 +225,11 @@ public String getDisplayName() {
* @param displayName the display name of this configuration setting.
*
* @return The updated {@link FeatureFlagConfigurationSetting} object.
* @throws IllegalArgumentException if the setting's {@code value} is an invalid JSON format.
*/
public FeatureFlagConfigurationSetting setDisplayName(String displayName) {
this.displayName = displayName;
updateSettingValue();
return this;
}

Expand All @@ -183,8 +238,8 @@ public FeatureFlagConfigurationSetting setDisplayName(String displayName) {
*
* @return the feature flag filters of this configuration setting.
*/
public Iterable<FeatureFlagFilter> getClientFilters() {
return Collections.unmodifiableList(clientFilters);
public List<FeatureFlagFilter> getClientFilters() {
return clientFilters;
}

/**
Expand All @@ -193,9 +248,11 @@ public Iterable<FeatureFlagFilter> getClientFilters() {
* @param clientFilters the feature flag filters of this configuration setting.
*
* @return The updated {@link FeatureFlagConfigurationSetting} object.
* @throws IllegalArgumentException if the setting's {@code value} is an invalid JSON format.
*/
public FeatureFlagConfigurationSetting setClientFilters(List<FeatureFlagFilter> clientFilters) {
this.clientFilters = clientFilters;
updateSettingValue();
return this;
}

Expand All @@ -208,6 +265,16 @@ public FeatureFlagConfigurationSetting setClientFilters(List<FeatureFlagFilter>
*/
public FeatureFlagConfigurationSetting addClientFilter(FeatureFlagFilter clientFilter) {
clientFilters.add(clientFilter);
updateSettingValue();
return this;
}

private void updateSettingValue() {
try {
super.setValue(writeFeatureFlagConfigurationSetting(this));
} catch (IOException exception) {
LOGGER.logExceptionAsError(new IllegalArgumentException(
"Can't parse Feature Flag configuration setting value.", exception));
}
}
}
Loading

0 comments on commit 9f0aa26

Please sign in to comment.