/** * Adds a settings consumer that accepts the values for two settings. * See {@link #addSettingsUpdateConsumer(Setting, Setting, BiConsumer, BiConsumer)} for details. */ public synchronized <A, B> void addSettingsUpdateConsumer(Setting<A> a, Setting<B> b, BiConsumer<A, B> consumer) { addSettingsUpdateConsumer(a, b, consumer, (i, j) -> {} ); }
/** * Adds a settings consumer with a predicate that is only evaluated at update time. * <p> * Note: Only settings registered in {@link SettingsModule} can be changed dynamically. * </p> * @param validator an additional validator that is only applied to updates of this setting. * This is useful to add additional validation to settings at runtime compared to at startup time. */ public synchronized <T> void addSettingsUpdateConsumer(Setting<T> setting, Consumer<T> consumer, Consumer<T> validator) { if (setting != get(setting.getKey())) { throw new IllegalArgumentException("Setting is not registered for key [" + setting.getKey() + "]"); } addSettingsUpdater(setting.newUpdater(consumer, logger, validator)); }
Settings.Builder settingsBuilder = Settings.builder(); final Predicate<String> canUpdate = (key) -> ( isFinalSetting(key) == false && // it's not a final setting ((onlyDynamic == false && get(key) != null) || isDynamicSetting(key))); for (String key : toApply.keySet()) { boolean isDelete = toApply.hasValue(key) == false; if (isDelete && (isValidDelete(key, onlyDynamic) || key.endsWith("*"))) { } else if (get(key) == null) { throw new IllegalArgumentException(type + " setting [" + key + "], not recognized"); } else if (isDelete == false && canUpdate.test(key)) { validate(key, toApply, false); // we might not have a full picture here do to a dependency validation settingsBuilder.copy(key, toApply); updates.copy(key, toApply); changed |= toApply.get(key).equals(target.get(key)) == false; } else { if (isFinalSetting(key)) { throw new IllegalArgumentException("final " + type + " setting [" + key + "], not updateable"); } else { changed |= applyDeletes(toRemove, target, k -> isValidDelete(k, onlyDynamic)); target.put(settingsBuilder.build()); return changed;
/** * Returns <code>true</code> if the given key is a valid delete key */ private boolean isValidDelete(String key, boolean onlyDynamic) { return isFinalSetting(key) == false && // it's not a final setting (onlyDynamic && isDynamicSetting(key) // it's a dynamicSetting and we only do dynamic settings || get(key) == null && key.startsWith(ARCHIVED_SETTINGS_PREFIX) // the setting is not registered AND it's been archived || (onlyDynamic == false && get(key) != null)); // if it's not dynamic AND we have a key }
/** * Adds a settings consumer for affix settings. Affix settings have a namespace associated to it that needs to be available to the * consumer in order to be processed correctly. */ public synchronized <T> void addAffixUpdateConsumer(Setting.AffixSetting<T> setting, BiConsumer<String, T> consumer, BiConsumer<String, T> validator) { ensureSettingIsRegistered(setting); addSettingsUpdater(setting.newAffixUpdater(consumer, logger, validator)); }
protected void validateSettingKey(Setting setting) { if (isValidKey(setting.getKey()) == false && (setting.isGroupSetting() && isValidGroupKey(setting.getKey()) || isValidAffixKey(setting.getKey())) == false || setting.getKey().endsWith(".0")) { throw new IllegalArgumentException("illegal settings key: [" + setting.getKey() + "]"); } }
throw new IllegalArgumentException("Setting must be a " + scope + " setting but has: " + setting.getProperties()); validateSettingKey(setting); Setting<?> overlappingSetting = findOverlappingSetting(setting, complexMatchers); if (overlappingSetting != null) { throw new IllegalArgumentException("complex setting key: [" + setting.getKey() + "] overlaps existing setting key: [" +
final List<RuntimeException> exceptions = new ArrayList<>(); for (final String key : settings.keySet()) { // settings iterate in deterministic fashion final Setting<?> setting = getRaw(key); if (((isPrivateSetting(key) || (setting != null && setting.isPrivateIndex())) && ignorePrivateSettings)) { continue; validate(key, settings, validateDependencies, validateInternalOrPrivateIndex); } catch (final RuntimeException ex) { exceptions.add(ex);
for (String key : settings.keySet()) { try { Setting<?> setting = get(key); if (setting != null) { setting.get(settings); builder.copy(key, settings); } else { if (key.startsWith(ARCHIVED_SETTINGS_PREFIX) || isPrivateSetting(key)) { builder.copy(key, settings); } else {
/** * Returns <code>true</code> if the setting for the given key is dynamically updateable. Otherwise <code>false</code>. */ public boolean isDynamicSetting(String key) { final Setting<?> setting = get(key); return setting != null && setting.isDynamic(); }
/** * Transactional interface to update settings. * @see Setting * @param <T> the type of the value of the setting */ public interface SettingUpdater<T> { /** * Returns true if this updaters setting has changed with the current update * @param current the current settings * @param previous the previous setting * @return true if this updaters setting has changed with the current update */ boolean hasChanged(Settings current, Settings previous); /** * Returns the instance value for the current settings. This method is stateless and idempotent. * This method will throw an exception if the source of this value is invalid. */ T getValue(Settings current, Settings previous); /** * Applies the given value to the updater. This methods will actually run the update. */ void apply(T value, Settings current, Settings previous); /** * Updates this updaters value if it has changed. * @return <code>true</code> iff the value has been updated. */
/** * Adds a settings consumer that is only executed if any setting in the supplied list of settings is changed. In that case all the * settings are specified in the argument are returned. * * Also automatically adds empty consumers for all settings in order to activate logging */ public synchronized void addSettingsUpdateConsumer(Consumer<Settings> consumer, List<? extends Setting<?>> settings) { addSettingsUpdater(Setting.groupedSettingsUpdater(consumer, settings)); }
private Setting<?> getRaw(String key) { Setting<?> setting = keySettings.get(key); if (setting != null) { return setting; } for (Map.Entry<String, Setting<?>> entry : complexMatchers.entrySet()) { if (entry.getValue().match(key)) { assert assertMatcher(key, 1); assert entry.getValue().hasComplexMatcher(); return entry.getValue(); } } return null; }
protected void validateSettingKey(Setting setting) { if (isValidKey(setting.getKey()) == false && (setting.isGroupSetting() && isValidGroupKey(setting.getKey()) || isValidAffixKey(setting.getKey())) == false) { throw new IllegalArgumentException("illegal settings key: [" + setting.getKey() + "]"); } }
/** * Returns <code>true</code> if the given key is a valid delete key */ private boolean isValidDelete(String key, boolean onlyDynamic) { return isFinalSetting(key) == false && // it's not a final setting (onlyDynamic && isDynamicSetting(key) // it's a dynamicSetting and we only do dynamic settings || get(key) == null && key.startsWith(ARCHIVED_SETTINGS_PREFIX) // the setting is not registered AND it's been archived || (onlyDynamic == false && get(key) != null)); // if it's not dynamic AND we have a key }
protected AbstractScopedSettings(Settings settings, Set<Setting<?>> settingsSet, Setting.Property scope) { super(settings); this.lastSettingsApplied = Settings.EMPTY; this.scope = scope; Map<String, Setting<?>> complexMatchers = new HashMap<>(); Map<String, Setting<?>> keySettings = new HashMap<>(); for (Setting<?> setting : settingsSet) { if (setting.getProperties().contains(scope) == false) { throw new IllegalArgumentException("Setting must be a " + scope + " setting but has: " + setting.getProperties()); } validateSettingKey(setting); if (setting.hasComplexMatcher()) { Setting<?> overlappingSetting = findOverlappingSetting(setting, complexMatchers); if (overlappingSetting != null) { throw new IllegalArgumentException("complex setting key: [" + setting.getKey() + "] overlaps existing setting key: [" + overlappingSetting.getKey() + "]"); } complexMatchers.putIfAbsent(setting.getKey(), setting); } else { keySettings.putIfAbsent(setting.getKey(), setting); } } this.complexMatchers = Collections.unmodifiableMap(complexMatchers); this.keySettings = Collections.unmodifiableMap(keySettings); }
final List<RuntimeException> exceptions = new ArrayList<>(); for (final String key : settings.keySet()) { // settings iterate in deterministic fashion final Setting<?> setting = getRaw(key); if (((isPrivateSetting(key) || (setting != null && setting.isPrivateIndex())) && ignorePrivateSettings)) { continue; validate(key, settings, validateDependencies, validateInternalOrPrivateIndex); } catch (final RuntimeException ex) { exceptions.add(ex);
for (Map.Entry<String, String> entry : settings.getAsMap().entrySet()) { try { Setting<?> setting = get(entry.getKey()); if (setting != null) { setting.get(settings); builder.put(entry.getKey(), entry.getValue()); } else { if (entry.getKey().startsWith(ARCHIVED_SETTINGS_PREFIX) || isPrivateSetting(entry.getKey())) { builder.put(entry.getKey(), entry.getValue()); } else {
ensureSettingIsRegistered(settingA); ensureSettingIsRegistered(settingB); SettingUpdater<Map<SettingUpdater<A>, A>> affixUpdaterA = settingA.newAffixUpdater((a,b)-> {}, logger, (a,b)-> {}); SettingUpdater<Map<SettingUpdater<B>, B>> affixUpdaterB = settingB.newAffixUpdater((a,b)-> {}, logger, (a,b)-> {}); addSettingsUpdater(new SettingUpdater<Map<String, Tuple<A, B>>>() {
/** * Returns <code>true</code> if the setting for the given key is final. Otherwise <code>false</code>. */ public boolean isFinalSetting(String key) { final Setting<?> setting = get(key); return setting != null && setting.isFinal(); }