Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Licensed under the MIT License.
package com.azure.spring.cloud.appconfiguration.config.implementation;

import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.FEATURE_FLAG_CONTENT_TYPE;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
Expand All @@ -24,6 +22,7 @@
import com.azure.data.appconfiguration.models.SecretReferenceConfigurationSetting;
import com.azure.data.appconfiguration.models.SettingSelector;
import com.azure.security.keyvault.secrets.models.KeyVaultSecret;
import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.FEATURE_FLAG_CONTENT_TYPE;

/**
* Azure App Configuration PropertySource unique per Store Label(Profile) combo.
Expand Down Expand Up @@ -68,7 +67,7 @@ class AppConfigurationApplicationSettingPropertySource extends AppConfigurationP
@Override
public void initProperties(List<String> keyPrefixTrimValues, Context context) throws InvalidConfigurationPropertyValueException {

List<String> labels = Arrays.asList(labelFilters);
List<String> labels = new ArrayList<>(Arrays.asList(labelFilters));
// Reverse labels so they have the right priority order.
Collections.reverse(labels);

Expand Down Expand Up @@ -114,7 +113,6 @@ protected void processConfigurationSettings(List<ConfigurationSetting> settings,
*
* @param key Application Setting name
* @param secretReference {"uri": "&lt;your-vault-url&gt;/secret/&lt;secret&gt;/&lt;version&gt;"}
* @return Key Vault Secret Value
* @throws InvalidConfigurationPropertyValueException
*/
private void handleKeyVaultReference(String key, SecretReferenceConfigurationSetting secretReference)
Expand Down Expand Up @@ -153,7 +151,7 @@ private String trimKey(String key, List<String> trimStrings) {
if (trimStrings != null) {
for (String trim : trimStrings) {
if (key.startsWith(trim)) {
return key.replaceFirst("^" + trim, "").replace('/', '.');
return key.substring(trim.length()).replace('/', '.');
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// Licensed under the MIT License.
package com.azure.spring.cloud.appconfiguration.config.implementation;

import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.PUSH_REFRESH;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
Expand All @@ -16,6 +14,7 @@
import com.azure.core.exception.HttpResponseException;
import com.azure.core.util.Context;
import com.azure.data.appconfiguration.models.ConfigurationSetting;
import static com.azure.spring.cloud.appconfiguration.config.implementation.AppConfigurationConstants.PUSH_REFRESH;
import com.azure.spring.cloud.appconfiguration.config.implementation.autofailover.ReplicaLookUp;
import com.azure.spring.cloud.appconfiguration.config.implementation.configuration.WatchedConfigurationSettings;
import com.azure.spring.cloud.appconfiguration.config.implementation.feature.FeatureFlagState;
Expand Down Expand Up @@ -229,7 +228,7 @@ static boolean refreshStoreCheck(AppConfigurationReplicaClient client, String or
* @param context the operation context
* @return true if a refresh should be triggered, false otherwise
*/
boolean refreshStoreFeatureFlagCheck(Boolean featureStoreEnabled,
boolean refreshStoreFeatureFlagCheck(boolean featureStoreEnabled,
AppConfigurationReplicaClient client, Context context) {
RefreshEventData eventData = new RefreshEventData();
String endpoint = client.getEndpoint();
Expand Down Expand Up @@ -382,6 +381,7 @@ private static void refreshWithoutTimeFeatureFlags(AppConfigurationReplicaClient
LOGGER.info("Configuration Refresh Event triggered by {}", FEATURE_FLAG_PREFIX);

eventData.setMessage(FEATURE_FLAG_PREFIX);
return;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import com.azure.data.appconfiguration.ConfigurationClient;
import com.azure.data.appconfiguration.models.ConfigurationSetting;
import com.azure.data.appconfiguration.models.ConfigurationSnapshot;
import com.azure.data.appconfiguration.models.FeatureFlagConfigurationSetting;
import com.azure.data.appconfiguration.models.SettingSelector;
import com.azure.data.appconfiguration.models.SnapshotComposition;
import com.azure.spring.cloud.appconfiguration.config.implementation.configuration.WatchedConfigurationSettings;
Expand Down Expand Up @@ -151,15 +150,14 @@ List<ConfigurationSetting> listSettings(SettingSelector settingSelector, Context
}

/**
* Gets configuration settings using watched configuration settings. This method retrieves all settings matching the
* selector and captures ETags for collection-based refresh monitoring.
*
* Lists configuration settings page by page, capturing ETags for collection-based refresh monitoring.
*
* @param settingSelector selector criteria for configuration settings
* @param context Azure SDK context for request correlation
* @return WatchedConfigurationSettings containing the retrieved configuration settings and match conditions
* @return WatchedConfigurationSettings containing the retrieved settings and match conditions
* @throws HttpResponseException if the request fails
*/
WatchedConfigurationSettings loadWatchedSettings(SettingSelector settingSelector, Context context) {
WatchedConfigurationSettings listSettingsByPage(SettingSelector settingSelector, Context context) {
List<ConfigurationSetting> configurationSettings = new ArrayList<>();
List<MatchConditions> checks = new ArrayList<>();
try {
Expand All @@ -182,39 +180,6 @@ WatchedConfigurationSettings loadWatchedSettings(SettingSelector settingSelector
}
}

/**
* Lists feature flags from the Azure App Configuration store.
*
* @param settingSelector selector criteria for feature flags
* @param context Azure SDK context for request correlation
* @return WatchedConfigurationSettings containing the retrieved feature flags and match conditions
* @throws HttpResponseException if the request fails
*/
WatchedConfigurationSettings listFeatureFlags(SettingSelector settingSelector, Context context)
throws HttpResponseException {
List<ConfigurationSetting> configurationSettings = new ArrayList<>();
List<MatchConditions> checks = new ArrayList<>();
try {
client.listConfigurationSettings(settingSelector, context).streamByPage().forEach(pagedResponse -> {
checks.add(
new MatchConditions().setIfNoneMatch(pagedResponse.getHeaders().getValue(HttpHeaderName.ETAG)));
for (ConfigurationSetting featureFlag : pagedResponse.getValue()) {
configurationSettings
.add((FeatureFlagConfigurationSetting) NormalizeNull.normalizeNullLabel(featureFlag));
}
});

// Needs to happen after or we don't know if the request succeeded or failed.
this.failedAttempts = 0;
settingSelector.setMatchConditions(checks);
return new WatchedConfigurationSettings(settingSelector, configurationSettings);
} catch (HttpResponseException e) {
throw handleHttpResponseException(e);
} catch (UncheckedIOException e) {
throw new AppConfigurationStatusException(e.getMessage(), null, null);
}
}

/**
* Lists configuration settings from a specific snapshot.
*
Expand Down Expand Up @@ -245,11 +210,26 @@ List<ConfigurationSetting> listSettingSnapshot(String snapshotName, Context cont
}
}

/**
* Checks if any watched configuration settings have been modified by comparing ETags.
*
* @param settingSelector selector with match conditions to check for modifications
* @param context Azure SDK context for request correlation
* @return true if any settings have been modified, false otherwise
* @throws HttpResponseException if the request fails
*/
boolean checkWatchKeys(SettingSelector settingSelector, Context context) {
List<PagedResponse<ConfigurationSetting>> results = client
.listConfigurationSettings(settingSelector, context)
.streamByPage().filter(pagedResponse -> pagedResponse.getStatusCode() != HTTP_NOT_MODIFIED).toList();
return !results.isEmpty();
try {
List<PagedResponse<ConfigurationSetting>> results = client
.listConfigurationSettings(settingSelector, context)
.streamByPage().filter(pagedResponse -> pagedResponse.getStatusCode() != HTTP_NOT_MODIFIED).toList();
this.failedAttempts = 0;
return !results.isEmpty();
} catch (HttpResponseException e) {
throw handleHttpResponseException(e);
} catch (UncheckedIOException e) {
throw new AppConfigurationStatusException(e.getMessage(), null, null);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public class AppConfigurationReplicaClientFactory {

/** Map of connection managers keyed by origin endpoint */
private static final Map<String, ConnectionManager> CONNECTIONS = new HashMap<>();
private final Map<String, ConnectionManager> connections = new HashMap<>();

/** List of configured stores for endpoint resolution */
private final List<ConfigStore> configStores;
Expand All @@ -31,11 +31,9 @@ public class AppConfigurationReplicaClientFactory {
AppConfigurationReplicaClientFactory(AppConfigurationReplicaClientsBuilder clientBuilder,
List<ConfigStore> configStores, ReplicaLookUp replicaLookUp) {
this.configStores = configStores;
if (CONNECTIONS.isEmpty()) {
for (ConfigStore store : configStores) {
ConnectionManager manager = new ConnectionManager(clientBuilder, store, replicaLookUp);
CONNECTIONS.put(manager.getMainEndpoint(), manager);
}
for (ConfigStore store : configStores) {
ConnectionManager manager = new ConnectionManager(clientBuilder, store, replicaLookUp);
connections.put(manager.getMainEndpoint(), manager);
}
}

Expand All @@ -45,7 +43,7 @@ public class AppConfigurationReplicaClientFactory {
* @return map of endpoint to connection manager
*/
public Map<String, ConnectionManager> getConnections() {
return CONNECTIONS;
return connections;
}

/**
Expand All @@ -56,7 +54,7 @@ public Map<String, ConnectionManager> getConnections() {
* @return the next active AppConfigurationReplicaClient
*/
AppConfigurationReplicaClient getNextActiveClient(String originEndpoint, boolean useLastActive) {
return CONNECTIONS.get(originEndpoint).getNextActiveClient(useLastActive);
return connections.get(originEndpoint).getNextActiveClient(useLastActive);
}

/**
Expand All @@ -65,7 +63,7 @@ AppConfigurationReplicaClient getNextActiveClient(String originEndpoint, boolean
* @param originEndpoint the origin configuration store endpoint
*/
void findActiveClients(String originEndpoint) {
CONNECTIONS.get(originEndpoint).findActiveClients();
connections.get(originEndpoint).findActiveClients();
}

/**
Expand All @@ -75,7 +73,7 @@ void findActiveClients(String originEndpoint) {
* @param endpoint the specific replica endpoint that failed
*/
void backoffClient(String originEndpoint, String endpoint) {
CONNECTIONS.get(originEndpoint).backoffClient(endpoint);
connections.get(originEndpoint).backoffClient(endpoint);
}

/**
Expand All @@ -86,7 +84,7 @@ void backoffClient(String originEndpoint, String endpoint) {
Map<String, AppConfigurationStoreHealth> getHealth() {
Map<String, AppConfigurationStoreHealth> health = new HashMap<>();

CONNECTIONS.forEach((key, value) -> health.put(key, value.getHealth()));
connections.forEach((key, value) -> health.put(key, value.getHealth()));

return health;
}
Expand Down Expand Up @@ -114,7 +112,7 @@ String findOriginForEndpoint(String endpoint) {
* @return duration in milliseconds until next client is available, or 0 if one is available now
*/
long getMillisUntilNextClientAvailable(String originEndpoint) {
return CONNECTIONS.get(originEndpoint).getMillisUntilNextClientAvailable();
return connections.get(originEndpoint).getMillisUntilNextClientAvailable();
}

/**
Expand All @@ -125,7 +123,7 @@ long getMillisUntilNextClientAvailable(String originEndpoint) {
* @param syncToken the new sync token to store
*/
void updateSyncToken(String originEndpoint, String endpoint, String syncToken) {
CONNECTIONS.get(originEndpoint).updateSyncToken(endpoint, syncToken);
connections.get(originEndpoint).updateSyncToken(endpoint, syncToken);
}

}
Loading