com.kik.config.ice.source.DebugDynamicConfigSource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ice Show documentation
Show all versions of ice Show documentation
Interface-based Guice configuration framework
The newest version!
/*
* Copyright 2016 Kik Interactive, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kik.config.ice.source;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.multibindings.MapBinder;
import com.kik.config.ice.exception.ConfigException;
import com.kik.config.ice.internal.ConfigDescriptor;
import com.kik.config.ice.internal.ConfigDescriptorHolder;
import com.kik.config.ice.internal.MethodIdProxyFactory;
import com.kik.config.ice.sink.ConfigEventSink;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
/**
* An {@link AbstractDynamicConfigSource} which allows direct manipulation of configuration values.
* Inject this config source and use {@link #set(Object)} and {@link #id(Class)} to identify and change configuration
* values.
* Example:
*
* {@literal @}Inject
* DebugDynamicConfigSource debugSource;
* // later in class, setting value of foo()
* debugSource.set(debugSource.id().foo()).toValue("abc");
* // Also, the value may be cleared:
* debugSource.set(debugSource.id().foo()).toEmpty();
*
*/
@Slf4j
@Singleton
public class DebugDynamicConfigSource extends AbstractDynamicConfigSource implements ConfigEventSink
{
private static final int CONFIG_SOURCE_PRIORITY_DEFAULT = 0;
@Inject
protected DebugDynamicConfigSource(ConfigDescriptorHolder configDescriptorHolder)
{
super(configDescriptorHolder.configDescriptors);
}
/**
* Returns an method-identifying proxy of the given config interface, used within a call to {@link #set(Object)}
* to identify the method for which its value is to be set or cleared.
*
* @param configInterface the config interface to be proxied
* @param the config interface class
* @return the method-identifying proxy
*/
public C id(final Class configInterface)
{
return MethodIdProxyFactory.getProxy(configInterface);
}
/**
* Returns an method-identifying proxy of the given config interface, used within a call to {@link #set(Object)}
* to identify the method for which its value is to be set or cleared.
*
* @param configInterface the config interface to be proxied
* @param scopeNameOpt the optional scope to identify the particular config value to modify
* @param the config interface class
* @return the method-identifying proxy
*/
public C id(final Class configInterface, final Optional scopeNameOpt)
{
return MethodIdProxyFactory.getProxy(configInterface, scopeNameOpt);
}
/**
* Provides the start of a call chain which identifies and sets a configuration value. Note that this needs to be
* used in conjunction with a method call to a method-identifying proxy, which can be retrieved via
* {@link #id(Class)}
*
* @param ignoredValueFromProxy The value returned by the method call against a method-identifying proxy. The actual
* value here is irrelevant and is ignored.
* @param The value type of the configuration entry to be changed
* @return a {@link DebugValueSetter} instance that will change the identified configuration value.
*/
public DebugValueSetter set(final V ignoredValueFromProxy)
{
final MethodIdProxyFactory.MethodAndScope lastProxyMethodAndScope = MethodIdProxyFactory.getLastIdentifiedMethodAndScope();
if (lastProxyMethodAndScope == null) {
throw new ConfigException("Failed to identify config method previous to calling overrideDefault");
}
final Optional configDescOpt = configDescriptors.stream()
.filter(desc -> desc.getMethod().equals(lastProxyMethodAndScope.getMethod()) && desc.getScope().equals(lastProxyMethodAndScope.getScopeOpt()))
.findAny();
final String configKey = configDescOpt.map(desc -> desc.getConfigName()).orElseThrow(
() -> new ConfigException("Config method identified is not correctly registered in the config system"));
final Class> configClass = getClass(configDescOpt.get().getConfigType());
return new DebugValueSetter()
{
@Override
public void toValue(final V value)
{
final String stringValue;
if (configClass != null && Collection.class.isAssignableFrom(configClass)) {
final Collection collection = (Collection) value;
stringValue = collection == null ? "" : (String) collection.stream()
.map(v -> "\"" + String.valueOf(v).replaceAll("\"", "\"\"") + "\"")
.collect(Collectors.joining(","));
}
else {
stringValue = value == null ? "" : String.valueOf(value);
}
fireEvent(configKey, Optional.ofNullable(stringValue));
}
@Override
public void toEmpty()
{
fireEvent(configKey, Optional.empty());
}
};
}
public interface DebugValueSetter
{
void toValue(V value);
void toEmpty();
}
/**
* A raw handle to cause this ConfigSource to be updated to the new value, emitting an event if it is different
* than the previous value.
* It is recommended to instead use {@link #set(Object)} to provide a type-safe value rather than using this method
* directly in tests.
*
* @param configName the string name of the configuration value to be fired
* @param valueOpt an Optional String value of the config value to provide to the system. Optional.empty()
* implies that the value has been "unset" for the purposes of this config source.
*/
@Override
public void fireEvent(String configName, Optional valueOpt) throws ConfigException
{
if (!subjectMap.containsKey(configName)) {
throw new ConfigException("Unknown configName {}", configName);
}
emitEvent(configName, valueOpt);
}
private static Class> getClass(Type type)
{
if (type instanceof Class) {
return (Class) type;
}
else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
}
else {
return null;
}
}
public static Module module()
{
return module(CONFIG_SOURCE_PRIORITY_DEFAULT);
}
public static Module module(final int configSourcePriority)
{
return new AbstractModule()
{
@Override
protected void configure()
{
MapBinder mapBinder = MapBinder.newMapBinder(binder(), Integer.class, DynamicConfigSource.class);
mapBinder.addBinding(configSourcePriority).to(DebugDynamicConfigSource.class);
bind(DebugDynamicConfigSource.class);
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy