io.helixservice.core.feature.AbstractFeature.java Source code

Java tutorial

Introduction

Here is the source code for io.helixservice.core.feature.AbstractFeature.java

Source

/*
 * @author Les Novell
 *
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *
 *      The Apache License v2.0 is available at
 *      http://www.opensource.org/licenses/apache2.0.php
 *
 */

package io.helixservice.core.feature;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import io.helixservice.core.component.Component;
import io.helixservice.core.component.ComponentRegistry;
import io.helixservice.core.container.Container;
import org.slf4j.Logger;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * Abstract base class from which all features should derive,
 * as it provides common functionality and default implementations.
 */
public abstract class AbstractFeature implements Feature {
    private Multimap<String, Component> componentsMap = ArrayListMultimap.create();
    private String featureName;

    /**
     * Construct the feature, setting the feature name based on the Java class name.
     */
    public AbstractFeature() {
        this.featureName = getClass().getSimpleName();
        register(this); // Register this feature component, enables finding features dependency resolution
    }

    /**
     * Construct this feature, with the provided feature name
     *
     * @param featureName Feature name
     */
    public AbstractFeature(String featureName) {
        this.featureName = featureName;
    }

    /**
     * Register component(s) created and owned by this feature
     * <p>
     * Components registered here are in a registry local to this feature.
     * These components will also be automatically aggregated
     * and registered with the HelixServer top-level registry.
     * <p>
     * If a component contains other components, then the entire
     * tree of components will be registered.
     *
     * @param components Components to register
     */
    public Feature register(Component... components) {
        for (Component component : components) {
            componentsMap.put(component.getComponentType(), component);
            register(component.getContainedComponents());
        }

        return this;
    }

    @Override
    public ComponentRegistry registerAllFrom(ComponentRegistry registry) {
        componentsMap.putAll(registry.getComponentMap());
        return this;
    }

    /**
     * Get this feature's name for debugging and logging
     *
     * @return The feature's name
     */
    @Override
    public String getFeatureName() {
        return featureName;
    }

    /**
     * Returns a map of registered components owned by this feature
     *
     * @return The map of components, where key is the component type name.
     */
    public Multimap<String, Component> getComponentMap() {
        return ArrayListMultimap.create(componentsMap);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<Component> findAllComponents() {
        return componentsMap.values();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T extends Component> Collection<T> findComponentByType(String componentType) {
        @SuppressWarnings("unchecked")
        Collection<T> result = (Collection<T>) componentsMap.get(componentType);

        if (result == null) {
            result = Collections.emptyList();
        }

        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T extends Component> T findComponentByType(String componentType, T defaultValue) {
        //noinspection unchecked
        return Iterables.getLast((Collection<T>) componentsMap.get(componentType), defaultValue);
    }

    /**
     * Logs the feature configuration to the provided logger.
     * <p>
     * This implements a generic way of logging features, so
     * subclasses should not need to implement their own logging code.
     *
     * @param logger Logger to write the feature details to
     */
    @Override
    public void logFeatureDetails(Logger logger) {
        logger.info("Feature " + getFeatureName() + " components:");
        logFactories(logger);
        logComponents(logger);
    }

    private void logComponents(Logger logger) {
        List<String> componentDescriptions = new ArrayList<>();

        for (String registrableTypeName : componentsMap.keySet()) {
            for (Component component : componentsMap.get(registrableTypeName)) {
                String componentDescription = component.getComponentDescription();
                if (componentDescription != null && !componentDescription.isEmpty()) {
                    componentDescriptions.add(
                            "   " + String.format("%1$-15s", registrableTypeName) + " " + componentDescription);
                }
            }
        }

        Collections.sort(componentDescriptions);
        componentDescriptions.forEach(logger::info);
    }

    private void logFactories(Logger logger) {
        Method[] declaredMethods = getClass().getDeclaredMethods();
        for (Method method : declaredMethods) {
            if (!"void".equals(method.getGenericReturnType().getTypeName())
                    && (method.getModifiers() & Modifier.PUBLIC) != 0) {
                logger.info("   {}  {}", String.format("%1$-15s", "FactoryMethod"),
                        method.getName() + "() => " + method.getGenericReturnType().getTypeName());
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void start(Container container) {

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void finish(Container container) {

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void stop(Container container) {

    }
}