All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.smallrye.beanbag.Scope Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
package io.smallrye.beanbag;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A (potentially nested) scope from which bean instances may be acquired.
 */
public final class Scope {
    private final Scope parent;
    private final Scope resolutionScope;
    private final List> beans;
    private final Map, List>> beansByType = new ConcurrentHashMap<>();
    private final BeanBag container;

    Scope(final BeanBag container, final Scope parent, final ScopeDefinition resolutionScope,
            final ScopeDefinition definition) {
        this.container = container;
        this.parent = parent;
        if (resolutionScope == null) {
            this.resolutionScope = this;
        } else {
            this.resolutionScope = new Scope(container, this, null, resolutionScope);
        }
        this.beans = Util.mapList(definition.getBeanDefinitions(), Bean::new, Bean[]::new);
    }

    @SuppressWarnings("unchecked")
    private  List> getBeansByType(Class type) {
        List> list = (List>) (List) beansByType.get(type);
        if (list == null) {
            // compute it
            if (parent != null) {
                list = new ArrayList<>(parent.getBeansByType(type));
            } else {
                list = new ArrayList<>();
            }
            for (Bean bean : beans) {
                if (bean.matchesByType(type)) {
                    list.add((Bean) bean);
                }
            }
            list.sort(Bean.byPriority());
            if (list.isEmpty()) {
                list = List.of();
            }
            final List> appearing = (List>) (List) beansByType.putIfAbsent(type,
                    (List>) (List) list);
            if (appearing != null) {
                list = appearing;
            }
        }
        return list;
    }

    /**
     * Get all constructable beans of the given type.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @return the (possibly empty) list of all matching beans
     * @param  the allowed bean type
     */
    public  List getAllBeans(Class type) {
        return getAllBeans(type, DependencyFilter.ACCEPT);
    }

    /**
     * Get all constructable beans of the given type.
     * The filter is applied to each bean to determine whether it should be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param filter the filter to apply to determine whether a given bean should be included (must not be {@code null})
     * @return the (possibly empty) list of all matching beans
     * @param  the allowed bean type
     */
    public  List getAllBeans(Class type, DependencyFilter filter) {
        return getAllBeans(type, "", filter);
    }

    /**
     * Get all constructable beans of the given type and name.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param name the name of the bean which should be returned, or {@code ""} for any (must not be {@code null})
     * @return the (possibly empty) list of all matching beans
     * @param  the allowed bean type
     */
    public  List getAllBeans(final Class type, final String name) {
        return getAllBeans(type, name, DependencyFilter.ACCEPT);
    }

    /**
     * Get all constructable beans of the given type and name.
     * The filter is applied to each bean to determine whether it should be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param name the name of the bean which should be returned, or {@code ""} for any (must not be {@code null})
     * @param filter the filter to apply to determine whether a given bean should be included (must not be {@code null})
     * @return the (possibly empty) list of all matching beans
     * @param  the allowed bean type
     */
    public  List getAllBeans(final Class type, final String name, DependencyFilter filter) {
        final List> beans = getBeansByType(type);
        if (beans.isEmpty()) {
            return List.of();
        }
        final List list = new ArrayList<>(beans.size());
        for (Bean bean : beans) {
            if ((name.isEmpty() || bean.getName().equals(name))
                    && filter.test(bean.getType(), bean.getName(), bean.getPriority())) {
                try {
                    final T instance = bean.get(resolutionScope);
                    if (instance != null) {
                        list.add(instance);
                    }
                } catch (Exception ignored) {
                    // do not include it
                }
            }
        }
        return List.copyOf(list);
    }

    /**
     * Get all constructable beans of the given type as a map.
     * The filter is applied to each bean to determine whether it should be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param filter the filter to apply to determine whether a given bean should be included (must not be {@code null})
     * @return the (possibly empty) list of all matching beans
     * @param  the allowed bean type
     */
    public  Map getAllBeansWithNames(final Class type, final DependencyFilter filter) {
        final List> beans = getBeansByType(type);
        if (beans.isEmpty()) {
            return Map.of();
        }
        final Map map = new LinkedHashMap<>(beans.size());
        for (Bean bean : beans) {
            // preserve priority order
            if (!map.containsKey(bean.getName()) && filter.test(bean.getType(), bean.getName(), bean.getPriority())) {
                final T instance = bean.get(resolutionScope);
                if (instance != null) {
                    map.put(bean.getName(), instance);
                }
            }
        }
        return Map.copyOf(map);
    }

    /**
     * Require a single bean with the given type.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @return the single bean (not {@code null})
     * @param  the allowed bean type
     * @throws NoSuchBeanException if the bean is not present
     * @throws BeanInstantiationException if some error occurred when instantiating the bean
     */
    public  T requireBean(Class type) {
        return getBean(type, "", false, DependencyFilter.ACCEPT);
    }

    /**
     * Require a single bean with the given type and name.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param name the name of the bean which should be returned, or {@code ""} for any (must not be {@code null})
     * @return the single bean (not {@code null})
     * @param  the allowed bean type
     * @throws NoSuchBeanException if the bean is not present
     * @throws BeanInstantiationException if some error occurred when instantiating the bean
     */
    public  T requireBean(Class type, String name) {
        return getBean(type, name, false, DependencyFilter.ACCEPT);
    }

    /**
     * Get a single bean with the given type, if it exists and can be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @return the single bean, or {@code null} if it is not present
     * @param  the allowed bean type
     */
    public  T getOptionalBean(Class type) {
        return getOptionalBean(type, "");
    }

    /**
     * Get a single bean with the given type and name, if it exists and can be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param name the name of the bean which should be returned, or {@code ""} for any (must not be {@code null})
     * @return the single bean, or {@code null} if it is not present
     * @param  the allowed bean type
     */
    public  T getOptionalBean(Class type, String name) {
        return getOptionalBean(type, name, DependencyFilter.ACCEPT);
    }

    /**
     * Get a single bean with the given type and name, if it exists and can be instantiated.
     * The filter is applied to each bean to determine whether it should be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param name the name of the bean which should be returned, or {@code ""} for any (must not be {@code null})
     * @param filter the filter to apply to determine whether a given bean should be included (must not be {@code null})
     * @return the single bean, or {@code null} if it is not present
     * @param  the allowed bean type
     */
    public  T getOptionalBean(Class type, String name, DependencyFilter filter) {
        return getBean(type, name, true, filter);
    }

    /**
     * Get a single bean with the given type and name, with configurable optionality.
     * The filter is applied to each bean to determine whether it should be instantiated.
     *
     * @param type the allowed bean type class (must not be {@code null})
     * @param name the name of the bean which should be returned, or {@code ""} for any (must not be {@code null})
     * @param optional {@code true} to return null if no bean matches, or {@code false} to throw an exception if no bean matches
     * @param filter the filter to apply to determine whether a given bean should be included (must not be {@code null})
     * @return the single bean, or {@code null} if it is not present
     * @param  the allowed bean type
     * @throws NoSuchBeanException if the bean is not present
     */
    public  T getBean(final Class type, final String name, final boolean optional, final DependencyFilter filter) {
        final List> beans = getBeansByType(type);
        List problems = null;
        for (Bean bean : beans) {
            try {
                if ((name.isEmpty() || bean.getName().equals(name))
                        && filter.test(bean.getType(), bean.getName(), bean.getPriority())) {
                    final T instance = bean.get(resolutionScope);
                    if (instance != null) {
                        return instance;
                    }
                }
            } catch (Exception e) {
                if (!optional) {
                    if (problems == null) {
                        problems = new ArrayList<>();
                    }
                    problems.add(e);
                }
            }
        }
        if (optional) {
            return null;
        }
        StringBuilder msgBuilder = new StringBuilder("No matching bean available: type is ");
        msgBuilder.append(type);
        if (!name.isEmpty()) {
            msgBuilder.append(", name is \"").append(name).append('"');
        }
        final NoSuchBeanException nbe = new NoSuchBeanException(msgBuilder.toString());
        if (problems != null) {
            problems.forEach(nbe::addSuppressed);
        }
        throw nbe;
    }

     T requireBean(final BeanDefinition definition) {
        Class type = definition.getType();
        final List> beans = getBeansByType(type);
        for (Bean bean : beans) {
            if (bean.getDefinition() == definition) {
                return bean.get(resolutionScope);
            }
        }
        StringBuilder msgBuilder = new StringBuilder("No matching bean available: type is ");
        msgBuilder.append(type);
        String name = definition.getName();
        if (!name.isEmpty()) {
            msgBuilder.append(", name is \"").append(name).append('"');
        }
        final NoSuchBeanException nbe = new NoSuchBeanException(msgBuilder.toString());
        throw nbe;
    }

    public BeanBag getContainer() {
        return container;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy