package org.togglz.core.repository.property;
import java.util.List;
import org.togglz.core.Feature;
import org.togglz.core.activation.UsernameActivationStrategy;
import org.togglz.core.repository.FeatureState;
import org.togglz.core.repository.StateRepository;
import org.togglz.core.util.Strings;
/**
* This implementation of {@link StateRepository} stores the state of features in a {@link Properties} format.
* The properties are managed through an implementation of {@link PropertySource} to manage the actual source
* of the property values.
* <p>
* The file format has changed since version 2.0.0 because of the new extendible activation strategy support. Old file formats
* will be automatically migrated. The new format looks like this:
* </p>
*
* <pre>
* FEATURE_ONE = true
* FEATURE_ONE.strategy = gradual
* FEATURE_ONE.param.percentage = 25
* FEATURE_TWO = false
* </pre>
*
* <p>
* A feature is enabled if the value is one of {@code true}, {@code yes}, {@code enable}, or {@code enabled}; any other
* value and the feature is considered disabled.
* </p>
*/
public class PropertyBasedStateRepository implements StateRepository {
private final PropertySource propertySource;
public PropertyBasedStateRepository(PropertySource propertySource) {
this.propertySource = propertySource;
}
public synchronized FeatureState getFeatureState(Feature feature) {
// update file if changed
propertySource.reloadIfUpdated();
// if we got this one, the feature is present in the repository
String enabledAsStr = propertySource.getValue(getEnabledPropertyName(feature), null);
if (enabledAsStr != null) {
// new state instance
FeatureState state = new FeatureState(feature);
state.setEnabled(isTrue(enabledAsStr));
// active strategy (may be null)
String strategy = propertySource.getValue(getStrategyPropertyName(feature), null);
state.setStrategyId(strategy);
// all parameters
String paramPrefix = getParameterPropertyName(feature, "");
for (String key : propertySource.getKeysStartingWith(paramPrefix)) {
String id = key.substring(paramPrefix.length());
String value = propertySource.getValue(key, null);
state.setParameter(id, value);
}
/*
* Backwards compatibility: if there are users stored in the old format, add them to the corresponding property
*/
List<String> additionalUsers = toList(propertySource.getValue(getUsersPropertyName(feature), null));
if (!additionalUsers.isEmpty()) {
// join the users to one list and update the property
List<String> currentUsers = toList(state.getParameter(UsernameActivationStrategy.PARAM_USERS));
currentUsers.addAll(additionalUsers);
state.setParameter(UsernameActivationStrategy.PARAM_USERS, Strings.join(currentUsers, ","));
// we should set strategy id if it is not yet set
if (state.getStrategyId() == null) {
state.setStrategyId(UsernameActivationStrategy.ID);
}
}
return state;
}
// the feature is not configured in the repository
return null;
}
public synchronized void setFeatureState(FeatureState featureState) {
// update file if changed
propertySource.reloadIfUpdated();
Feature feature = featureState.getFeature();
PropertySource.Editor editor = propertySource.getEditor();
// enabled
String enabledKey = getEnabledPropertyName(feature);
String enabledValue = featureState.isEnabled() ? "true" : "false";
editor.setValue(enabledKey, enabledValue);
// write strategy id, will be removed if it is null
editor.setValue(getStrategyPropertyName(feature), featureState.getStrategyId());
// parameters
String paramPrefix = getParameterPropertyName(feature, "");
editor.removeKeysStartingWith(paramPrefix);
for (String id : featureState.getParameterNames()) {
String key = getParameterPropertyName(feature, id);
editor.setValue(key, featureState.getParameter(id));
}
// remove the old users property if it still exists from the old format
editor.setValue(getUsersPropertyName(feature), null);
// write
editor.commit();
}
private static String getEnabledPropertyName(Feature feature) {
return feature.name();
}
private static String getStrategyPropertyName(Feature feature) {
return feature.name() + ".strategy";
}
private static String getParameterPropertyName(Feature feature, String parameter) {
return feature.name() + ".param." + parameter;
}
private static String getUsersPropertyName(Feature feature) {
return feature.name() + ".users";
}
private static boolean isTrue(String s) {
return s != null
&& ("true".equalsIgnoreCase(s.trim()) || "yes".equalsIgnoreCase(s.trim())
|| "enabled".equalsIgnoreCase(s.trim()) || "enable".equalsIgnoreCase(s.trim()));
}
private static List<String> toList(String input) {
return Strings.splitAndTrim(input, ",");
}
}