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

org.zodiac.autoconfigure.web.remote.smart.SmartHandlerMappingRegistrar Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.autoconfigure.web.remote.smart;

import java.util.Set;
import java.util.function.Predicate;

import org.slf4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.SingletonBeanRegistry;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.zodiac.commons.logging.SmartSlf4jLoggerFactory;
import org.zodiac.commons.reflection.ObjectInstantiators;
import org.zodiac.commons.util.Asserts;
import org.zodiac.commons.util.Colls;
import org.zodiac.commons.util.lang.Strings;
import org.zodiac.commons.util.spring.Springs;

public class SmartHandlerMappingRegistrar
        implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware, BeanFactoryAware {
    protected final Logger log = SmartSlf4jLoggerFactory.getLogger(getClass());

    private ResourceLoader resourceLoader;
    private Environment environment;
    @SuppressWarnings("unused")
    private BeanFactory beanFactory;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = Asserts.notNullOf(resourceLoader, "resourceLoader");
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = Asserts.notNullOf(environment, "environment");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = Asserts.notNullOf(beanFactory, "beanFactory");
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes attrs = AnnotationAttributes
                .fromMap(metadata.getAnnotationAttributes(EnableSmartRequestMapping.class.getName()));
        if (null != attrs) {
            BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);

            /*Register rqeust handler mapping.*/
            if (Springs.isReactiveWeb(getClass().getClassLoader(), environment, resourceLoader)) {
                /*Reactive WebFlux .*/
                registerSmartHandlerMappingConfigurer(metadata, attrs, registry, WebFluxSmartHandlerMappingConfiguration.class,
                        beanNameGenerator);
            } else if (Springs.isServletWeb(getClass().getClassLoader(), environment, resourceLoader)) {
                /*Servlet WebMvc .*/
                registerSmartHandlerMappingConfigurer(metadata, attrs, registry, WebMvcSmartHandlerMappingConfiguration.class,
                        beanNameGenerator);
            }
        }
    }

    protected void registerSmartHandlerMappingConfigurer(AnnotationMetadata metadata, AnnotationAttributes attrs,
            BeanDefinitionRegistry registry, Class beanClass, BeanNameGenerator beanNameGenerator) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);

        builder.addPropertyValue(EnableSmartRequestMapping.PACKAGE_PATTERNS, resolvePackagePatterns(metadata, attrs));
        builder.addPropertyValue(EnableSmartRequestMapping.PACKAGE_PATTERNS_FOR_INCLUDE,attrs.getBoolean(EnableSmartRequestMapping.PACKAGE_PATTERNS_FOR_INCLUDE));
        builder.addPropertyValue(EnableSmartRequestMapping.FILTERS, resolveIncludeFilters(attrs, registry));
        builder.addPropertyValue(EnableSmartRequestMapping.OVERRIDE_AMBIGUOUS, attrs.getBoolean(EnableSmartRequestMapping.OVERRIDE_AMBIGUOUS));

        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
        registry.registerBeanDefinition(beanName, beanDefinition);
    }

    @SuppressWarnings("unchecked")
    private Predicate>[] resolveIncludeFilters(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
        return Colls.safeArrayToList(annoAttrs.getClassArray(EnableSmartRequestMapping.FILTERS)).stream()
            .map(c -> ObjectInstantiators.newInstance(c)).toArray(Predicate[]::new);
    }

    /**
     * It'd better to use BeanNameGenerator instance that should reference
     * {@link ConfigurationClassPostProcessor#componentScanBeanNameGenerator},
     * thus it maybe a potential problem on bean name generation.
     *
     * @param registry {@link BeanDefinitionRegistry}
     * @return {@link BeanNameGenerator} instance
     * @see SingletonBeanRegistry
     * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
     * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions
     */
    private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) {
        BeanNameGenerator beanNameGenerator = null;
        if (registry instanceof SingletonBeanRegistry) {
            SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);
            beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
        }
        if (beanNameGenerator == null) {
            log.warn("BeanNameGenerator bean can't be found in BeanFactory with name [" + AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR
                    + "], BeanNameGenerator will be a instance of " + AnnotationBeanNameGenerator.class.getName()
                    + " , it maybe a potential problem on bean name generation.");
            beanNameGenerator = new AnnotationBeanNameGenerator();
        }
        return beanNameGenerator;
    }

    private String[] resolvePackagePatterns(AnnotationMetadata metadata, AnnotationAttributes attrs) {
        return getPackagePatterns(metadata, attrs).stream().filter(v -> Strings.notBlank(v))
                .map(v -> environment.resolveRequiredPlaceholders(v)).toArray(String[]::new);
    }

    private Set getPackagePatterns(AnnotationMetadata metadata, AnnotationAttributes attrs) {
        Set basePackages = Colls.set();
        for (String pkg : attrs.getStringArray("value")) {
            if (Strings.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        for (String pkg : attrs.getStringArray(EnableSmartRequestMapping.PACKAGE_PATTERNS)) {
            if (Strings.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        /*
         * [Must Ignore] We must strictly handle only the specified values, so
         * that we can be transparent to the outside world, because the
         * conditions here are too sensitive.
         */
        // if (basePackages.isEmpty()) {
        // basePackages.add(ClassUtils.getPackageName(metadata.getClassName()));
        // }
        return basePackages;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy