package ru.vyarus.dropwizard.guice.module.context;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import ru.vyarus.dropwizard.guice.module.context.info.ItemInfo;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Public api for collected guicey configuration info. In contrast to {@link ConfigurationContext},
* used during configuration, contains only configuration item classes.
* <p>
* Configuration info may be used for any kind of diagnostics: configuration logging, configuration tree rendering,
* automatic configuration warnings generation etc.
* <p>
* Configuration items are stored in registration order. Information querying is implemented with help of java 8
* {@link java.util.function.Predicate}.
* <p>
* Available for direct injection, but prefer accessing from
* {@link ru.vyarus.dropwizard.guice.module.GuiceyConfigurationInfo#getData()}.
*
* @author Vyacheslav Rusakov
* @see ru.vyarus.dropwizard.guice.module.GuiceyConfigurationInfo as high level info api
* @see ConfigItem for the list of available confiugration items
* @since 06.07.2016
*/
public final class ConfigurationInfo {
// required structure to preserve registration order
private final Multimap<ConfigItem, Class<?>> itemsHolder = LinkedHashMultimap.create();
private final Map<Class<?>, ItemInfo> detailsHolder = Maps.newHashMap();
public ConfigurationInfo(final ConfigurationContext context) {
// convert all objects into types (more suitable for analysis)
for (ConfigItem type : ConfigItem.values()) {
for (Object item : context.getItems(type)) {
final Class<?> itemType = getType(item);
itemsHolder.put(type, itemType);
detailsHolder.put(itemType, context.getInfo(item));
}
}
}
/**
* Pay attention that disabled (or disabled and never registered) items are also returned.
*
* @param type configuration item type
* @param <T> expected class
* @return registered item classes of required type in registration order or empty list if nothing registered
*/
@SuppressWarnings("unchecked")
public <T> List<Class<T>> getItems(final ConfigItem type) {
final Collection res = itemsHolder.get(type);
return res.isEmpty() ? Collections.<Class<T>>emptyList() : (List<Class<T>>) Lists.newArrayList(res);
}
/**
* Used to query items of one configuration type (e.g. only installers or bundles). Some common filters are
* predefined in {@link Filters}. Use {@link Predicate#and(Predicate)}, {@link Predicate#or(Predicate)}
* and {@link Predicate#negate()} to reuse default filters.
* <p>
* Pay attention that disabled (or disabled and never registered) items are also returned.
*
* @param type configuration item type
* @param filter predicate to filter definitions
* @param <T> expected class
* @param <K> expected info container class
* @return registered item classes in registration order, filtered with provided filter or empty list
*/
public <T, K extends ItemInfo> List<Class<T>> getItems(final ConfigItem type, final Predicate<K> filter) {
final List<Class<T>> items = getItems(type);
return filter(items, filter);
}
/**
* Used to query items of all configuration types. May be useful to build configuration tree (e.g. to search
* all items configured by bundle or by classpath scan). Some common filters are
* predefined in {@link Filters}. Use {@link Predicate#and(Predicate)}, {@link Predicate#or(Predicate)}
* and {@link Predicate#negate()} to reuse default filters.
* <p>
* Pay attention that disabled (or disabled and never registered) items are also returned.
*
* @param filter predicate to filter definitions
* @return registered item classes in registration order, filtered with provided filter or empty list
*/
@SuppressWarnings("unchecked")
public List<Class<Object>> getItems(final Predicate<ItemInfo> filter) {
final List<Class<Object>> items = (List) Lists.newArrayList(itemsHolder.values());
return filter(items, filter);
}
/**
* @param item configured item type
* @param <T> expected configuration container type
* @return item configuration info or null if item not registered
*/
@SuppressWarnings("unchecked")
public <T extends ItemInfo> T getInfo(final Class<?> item) {
return (T) detailsHolder.get(item);
}
private Class<?> getType(final Object item) {
return item instanceof Class ? (Class) item : item.getClass();
}
private <T, K extends ItemInfo> List<Class<T>> filter(final List<Class<T>> items, final Predicate<K> filter) {
return items.stream().filter(it -> filter.test(getInfo(it))).collect(Collectors.toList());
}
}