001/*
002 * JGrapes Event Driven Framework
003 * Copyright (C) 2017-2018 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 * 
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.core;
020
021import java.util.Arrays;
022import java.util.Collections;
023import java.util.List;
024import java.util.Map;
025import java.util.ServiceLoader;
026import java.util.function.Function;
027
028/**
029 * A component that collects all component factory services of 
030 * a given type and uses each to create one or more components
031 * that are then attached to the component collector instance.
032 * 
033 * Effectively, the component collector leverages the 
034 * mechanism provided by the service loader to determine
035 * the component tree that is built eventually at 
036 * "link time".
037 * 
038 * @deprecated This class has been moved to 
039 * {@link org.jgrapes.util.ComponentCollector}.
040 * 
041 * @param <F> the component factory type
042 */
043@Deprecated(since = "1.3")
044public class ComponentCollector<F extends ComponentFactory>
045        extends Component {
046
047    private static final List<Map<Object, Object>> SINGLE_DEFAULT
048        = Arrays.asList(Collections.emptyMap());
049
050    /**
051     * Creates a new collector that collects the factories of the given 
052     * type and uses each to create one or more instances with this 
053     * component's (the component collector's) channel. 
054     * 
055     * Before instances are created, the `matcher` function is 
056     * invoked with the name of the class of the component
057     * to be created as argument. The list of maps returned is
058     * used to create components, passing each element in the list
059     * as parameter to {@link ComponentFactory#create(Channel, Map)}.
060     * 
061     * @param factoryClass the factory class
062     * @param componentChannel this component's channel
063     * @param matcher the matcher function
064     */
065    public ComponentCollector(
066            Class<F> factoryClass, Channel componentChannel,
067            Function<String, List<Map<Object, Object>>> matcher) {
068        super(componentChannel);
069        ServiceLoader<F> serviceLoader = ServiceLoader.load(factoryClass);
070        for (F factory : serviceLoader) {
071            List<Map<Object, Object>> configs = matcher.apply(
072                factory.componentType().getName());
073            for (Map<Object, Object> config : configs) {
074                factory.create(channel(), config).ifPresent(
075                    component -> attach(component));
076            }
077        }
078    }
079
080    /**
081     * Utility constructor that uses each factory to create a single
082     * instance, using an empty map as properties.
083     * 
084     * @param factoryClass the factory class
085     * @param componentChannel this component's channel
086     */
087    public ComponentCollector(
088            Class<F> factoryClass, Channel componentChannel) {
089        this(factoryClass, componentChannel, type -> SINGLE_DEFAULT);
090    }
091}