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.Collections;
022import java.util.Map;
023import java.util.Optional;
024import java.util.ServiceLoader;
025
026/**
027 * A general purpose factory interface for components.
028 * 
029 * In some use cases, components may not be known at compile-time, but
030 * only made available at run-time. The usual pattern for this is to lookup
031 * a factory service using the {@link ServiceLoader} and create the
032 * components using the factory (or factories) found.
033 * 
034 * Because JGrapes components interact with their environment only
035 * through events, they do not provide special APIs and it is possible
036 * to define this generic factory service interface.
037 * Of course, lookup by the {@link ServiceLoader} will usually be done
038 * using a derived interface (or base class) that represents the special
039 * kind of components required and allows an invocation
040 * of {@link ServiceLoader#load(Class)} that returns a "filtered"
041 * set of factories.
042 * 
043 * @since 1.3
044 */
045public interface ComponentFactory {
046
047    /**
048     * Assigns standard properties from the given properties to the
049     * component.
050     * 
051     * Currently, the only standard property of a component is its name.
052     *
053     * @param component the component
054     * @param properties the properties
055     * @return the optional
056     */
057    static ComponentType setStandardProperties(
058            ComponentType component, Map<?, ?> properties) {
059        if (properties.containsKey("name")) {
060            Components.manager(component)
061                .setName((String) properties.get("name"));
062        }
063        return component;
064    }
065
066    /**
067     * Returns the type of the components created by this factory.
068     * 
069     * @return the component type
070     */
071    Class<? extends ComponentType> componentType();
072
073    /**
074     * Creates a new component with its channel set to
075     * itself.
076     * 
077     * @return the component
078     */
079    default ComponentType create() {
080        return create(Channel.SELF);
081    }
082
083    /**
084     * Creates a new component with its channel set to the given 
085     * channel.
086     * 
087     * @param componentChannel the channel that the component's 
088     * handlers listen on by default and that 
089     * {@link Manager#fire(Event, Channel...)} sends the event to
090     * @return the component
091     */
092    default ComponentType create(Channel componentChannel) {
093        return create(componentChannel, Collections.emptyMap()).get();
094    }
095
096    /**
097     * Creates a new component with its channel set to the given 
098     * channel using the given additional properties. If the requested
099     * properties or combination of properties cannot be provided by
100     * the component, the factory may return an empty {@link Optional}. 
101     * 
102     * @param componentChannel the channel that the component's 
103     * handlers listen on by default and that 
104     * {@link Manager#fire(Event, Channel...)} sends the event to 
105     * @param properties additional properties for the creation of the
106     * component
107     * @return the component
108     */
109    Optional<ComponentType> create(
110            Channel componentChannel, Map<?, ?> properties);
111}