Extendable.java

/**
 * Copyright (c) 2017, RTE (http://www.rte-france.com)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * SPDX-License-Identifier: MPL-2.0
 */
package com.powsybl.commons.extensions;

import java.util.Collection;

/**
 * @author Mathieu Bague {@literal <mathieu.bague at rte-france.com>}
 */
public interface Extendable<O> {

    /**
     * Add en extension to this extendable object.
     *
     * @param type      the extension class type
     * @param extension the extension
     * @param <E>       the extension type
     */
    <E extends Extension<O>> void addExtension(Class<? super E> type, E extension);

    /**
     * Get an extension based on its class type.
     *
     * @param type the extension class type
     * @param <E>  the extension type
     * @return the extension mapped to the class type or null if not found
     */
    <E extends Extension<O>> E getExtension(Class<? super E> type);

    /**
     * Get an extension based on its name.
     *
     * @param name the extension name
     * @return the extension mapped to the name or null if not found
     */
    <E extends Extension<O>> E getExtensionByName(String name);

    /**
     * Remove an extension based on its class type.
     *
     * @param type the extension class type
     * @param <E>  the extension type
     * @return true if the extension has been removed false if extension has not been found
     */
    <E extends Extension<O>> boolean removeExtension(Class<E> type);

    /**
     * Get all extensions associated with this extendable object..
     *
     * @return all extensions associated to this extendable object.
     */
    <E extends Extension<O>> Collection<E> getExtensions();

    /**
     * Returns a name that is used to find matching {@link ExtensionAdderProvider}s
     * when selecting implementations of extensions in {@link #newExtension}. This
     * is meant to be overriden by extendables when multiple implementations exist.
     *
     * @return the name
     */
    default String getImplementationName() {
        return "Default";
    }

    /**
     * Returns an extensionAdder to build and add an extension for this extendable.
     * <p>
     * The extension implementation is selected at runtime based on matching the
     * {@link #getImplementationName} of this extendable to the
     * {@link ExtensionAdderProvider#getImplementationName} of a provider.
     * Implementations are loaded with java's {@link java.util.ServiceLoader} using
     * the ExtensionAdderProvider interface.
     *
     * @param type The interface of the ExtensionAdder
     * @return the adder
     */
    // Don't bother all the way with generics because the this is a runtime system
    // that doesn't know generics. We do check that the builder is from the the same
    // extendable class T as "this".
    default <E extends Extension<O>, B extends ExtensionAdder<O, E>> B newExtension(Class<B> type) {
        ExtensionAdderProvider provider = ExtensionAdderProviders.findCachedProvider(getImplementationName(), type);
        return (B) provider.newAdder(this);
    }

}