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

io.devbench.uibuilder.spring.startup.RegistryInitializer Maven / Gradle / Ivy

/*
 *
 * Copyright © 2018 Webvalto Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.devbench.uibuilder.spring.startup;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import io.devbench.uibuilder.annotations.ControllerBean;
import io.devbench.uibuilder.api.exceptions.InternalResolverException;
import io.devbench.uibuilder.api.exceptions.NoUniqueBeanNameFoundException;
import io.devbench.uibuilder.api.member.scanner.MemberScanner;
import io.devbench.uibuilder.api.parse.backendtemplate.BackendTemplateManager;
import io.devbench.uibuilder.components.i18n.pageloaderprocessor.CollectI18NMessagesProcessor;
import io.devbench.uibuilder.core.controllerbean.ControllerBeanManager;
import io.devbench.uibuilder.core.controllerbean.ControllerBeanProvidersHolder;
import io.devbench.uibuilder.core.page.PageLoader;
import io.devbench.uibuilder.core.page.pageloaderprocessors.AddJsModuleImportsProcessor;
import io.devbench.uibuilder.core.parse.PageTransformersRegistry;
import io.devbench.uibuilder.core.parse.ParseInterceptorsRegistry;
import io.devbench.uibuilder.core.startup.ComponentTagRegistry;
import io.devbench.uibuilder.data.api.datasource.DataSource;
import io.devbench.uibuilder.data.api.datasource.DataSourceManager;
import io.devbench.uibuilder.data.api.datasource.DataSourceProvider;
import io.devbench.uibuilder.data.api.datasource.DataSourceSelector;
import io.devbench.uibuilder.data.api.exceptions.DataSourceRegistryException;
import io.devbench.uibuilder.data.api.filter.validation.FilterValidationExecutor;
import io.devbench.uibuilder.i18n.core.I;
import io.devbench.uibuilder.i18n.core.interfaces.LanguageProvider;
import io.devbench.uibuilder.spring.configuration.basepackages.UIBuilderScanPackages;
import io.devbench.uibuilder.spring.data.BasicSpringDataSourceProvider;
import io.devbench.uibuilder.spring.data.SpringDataSourceProvider;
import io.devbench.uibuilder.spring.scanner.MemberComponentProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
public class RegistryInitializer {

    private final ApplicationContext applicationContext;

    private final UIBuilderScanPackages scanPackages;

    public RegistryInitializer(ApplicationContext applicationContext, UIBuilderScanPackages scanPackages) throws Exception {
        this.applicationContext = applicationContext;
        this.scanPackages = scanPackages;
        initializeMemberScanner();
        initializeComponentTagRegistry();
        initializeDataSourceManager();
        initializeParseInterceptors();
        initializeBackendTemplateManager();
        initializeLanguageProvider();
        initializePageTransformers();
        initializeControllerBeanManager();
        initializeFilterValidatorFacory();
        PageLoader.registerProcessorAfter(AddJsModuleImportsProcessor.class, new CollectI18NMessagesProcessor());
    }

    private void initializeFilterValidatorFacory() {
        FilterValidationExecutor.registerToActiveContext();
    }

    private void initializeMemberScanner() {
        MemberScanner.registerToActiveContext(
            this::findClassesAnnotatedWith,
            this::findClassesBySuperType
        );
    }

    @SuppressWarnings("unchecked")
    private void initializeDataSourceManager() {
        SpringDataSourceProvider dataSourceProvider = findSpringDataSourceProvider();
        Map, Set>> annotatedClasses = dataSourceProvider.getInterestedAnnotationTypes().stream()
            .collect(Collectors.toMap(Function.identity(), annotationType -> findClassesAnnotatedWith(annotationType, true)));
        dataSourceProvider.initialize(annotatedClasses);
        DataSourceManager.registerToActiveContext((DataSourceProvider, ? super DataSourceSelector>) dataSourceProvider);
    }

    private SpringDataSourceProvider findSpringDataSourceProvider() {
        List providerNames = Arrays.asList(applicationContext.getBeanNamesForType(SpringDataSourceProvider.class));
        if (providerNames.size() == 1) {
            return applicationContext.getBean(SpringDataSourceProvider.class);
        } else {
            String foundProviderName = providerNames.stream()
                .filter(providerName -> !BasicSpringDataSourceProvider.BASIC_SPRING_DATA_SOURCE_PROVIDER_BEAN_NAME.equals(providerName))
                .findFirst()
                .orElseThrow(() -> new DataSourceRegistryException("No available data source provider found"));
            return applicationContext.getBean(foundProviderName, SpringDataSourceProvider.class);
        }
    }

    private void initializeLanguageProvider() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Config conf = ConfigFactory.load();
        I.loadTranslations(conf.getStringList("translationsDir").get(0));
        I.setLanguageProvider((LanguageProvider) Class.forName(conf.getString("activeLanguageProvider")).newInstance());
    }

    private void initializeComponentTagRegistry() {
        ComponentTagRegistry.registerToActiveContext();
    }

    private void initializePageTransformers() {
        PageTransformersRegistry.registerToActiveContext();
    }

    private void initializeParseInterceptors() {
        ParseInterceptorsRegistry.registerToActiveContext();
    }

    private void initializeBackendTemplateManager() {
        BackendTemplateManager.registerToActiveContext();
    }

    private void initializeControllerBeanManager() {
        ControllerBeanProvidersHolder providersHolder = ControllerBeanProvidersHolder.builder()
            .beanInstanceByClass(applicationContext::getBean)
            .beanInstanceByName(applicationContext::getBean)
            .beanNameByClass(this::getUniqueBeanNameForControllerBeanType)
            .build();

        ControllerBeanManager.registerToActiveContext(providersHolder, ControllerBean.class);
    }

    private Set> findClassesAnnotatedWith(Class annotationType, boolean considerInterfaces) {
        MemberComponentProvider provider = new MemberComponentProvider(considerInterfaces, applicationContext.getEnvironment());
        provider.setResourceLoader(applicationContext);
        provider.addIncludeFilter(new AnnotationTypeFilter(annotationType));
        return findActualClassesByComponentProvider(provider).collect(Collectors.toSet());
    }

    @SuppressWarnings("unchecked")
    private  Set> findClassesBySuperType(Class superClass, boolean considerInterfaces) {
        MemberComponentProvider provider = new MemberComponentProvider(considerInterfaces, applicationContext.getEnvironment());
        provider.setResourceLoader(applicationContext);
        provider.addIncludeFilter(new AssignableTypeFilter(superClass));
        return findActualClassesByComponentProvider(provider)
            .map(clazz -> ((Class) clazz))
            .collect(Collectors.toSet());
    }

    private Stream> findActualClassesByComponentProvider(ClassPathScanningCandidateComponentProvider provider) {
        return scanPackages.getScanPackages().stream()
            .map(provider::findCandidateComponents)
            .flatMap(Collection::stream)
            .map(this::getBeanClass);
    }

    private String getUniqueBeanNameForControllerBeanType(Class clazz) {
        String[] beanNamesForType = applicationContext.getBeanNamesForType(clazz);
        if (beanNamesForType.length == 1) {
            return beanNamesForType[0];
        } else {
            return getControllerBeanNameFromAnnotation(clazz)
                .orElseThrow(() -> new NoUniqueBeanNameFoundException(clazz));
        }
    }

    private Optional getControllerBeanNameFromAnnotation(Class clazz) {
        ControllerBean annotation = clazz.getAnnotation(ControllerBean.class);
        if (annotation != null && !annotation.value().trim().isEmpty()) {
            return Optional.of(annotation.value());
        } else {
            Class superClass = clazz.getSuperclass();
            return superClass != null ? getControllerBeanNameFromAnnotation(superClass) : Optional.empty();
        }
    }

    private Class getBeanClass(BeanDefinition beanDefinition) {
        AbstractBeanDefinition definition = (AbstractBeanDefinition) beanDefinition;
        Class beanClass;
        if (definition.hasBeanClass()) {
            beanClass = definition.getBeanClass();
        } else {
            try {
                beanClass = definition.resolveBeanClass(applicationContext.getClassLoader());
            } catch (ClassNotFoundException e) {
                throw new InternalResolverException(e);
            }
        }
        return beanClass;
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy