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

net.n2oapp.framework.config.N2oApplicationBuilder Maven / Gradle / Ivy

There is a newer version: 7.28.2
Show newest version
package net.n2oapp.framework.config;

import net.n2oapp.framework.api.MetadataEnvironment;
import net.n2oapp.framework.api.metadata.Compiled;
import net.n2oapp.framework.api.metadata.Source;
import net.n2oapp.framework.api.metadata.aware.NamespaceUriAware;
import net.n2oapp.framework.api.metadata.compile.*;
import net.n2oapp.framework.api.metadata.jackson.ComponentType;
import net.n2oapp.framework.api.metadata.io.NamespaceIO;
import net.n2oapp.framework.api.metadata.io.ProxyNamespaceIO;
import net.n2oapp.framework.api.metadata.pipeline.*;
import net.n2oapp.framework.api.metadata.validate.SourceValidator;
import net.n2oapp.framework.api.pack.MetadataPack;
import net.n2oapp.framework.api.pack.XmlIOBuilder;
import net.n2oapp.framework.api.reader.SourceLoader;
import net.n2oapp.framework.api.register.DynamicMetadataProvider;
import net.n2oapp.framework.api.register.MetaType;
import net.n2oapp.framework.api.register.SourceInfo;
import net.n2oapp.framework.api.register.route.RouteInfo;
import net.n2oapp.framework.api.register.scan.MetadataScanner;
import net.n2oapp.framework.config.compile.pipeline.N2oEnvironment;
import net.n2oapp.framework.config.compile.pipeline.N2oPipelineSupport;
import net.n2oapp.framework.config.factory.AwareFactorySupport;
import net.n2oapp.framework.config.register.route.N2oRouter;
import net.n2oapp.framework.config.test.SimplePropertyResolver;
import net.n2oapp.properties.OverrideProperties;
import net.n2oapp.properties.reader.PropertiesReader;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.PropertyResolver;

import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Stream;

/**
 * Конструктор окружения {@link N2oEnvironment} и конвейера сборки метаданных {@link ReadPipeline}
 */
public class N2oApplicationBuilder implements XmlIOBuilder, PipelineSupport {
    private static final Logger logger = LoggerFactory.getLogger(N2oApplicationBuilder.class);

    private MetadataEnvironment environment;

    public N2oApplicationBuilder() {
        this.environment = new N2oEnvironment();
    }

    public N2oApplicationBuilder(MetadataEnvironment environment) {
        this.environment = environment;
    }

    @SafeVarargs
    public final N2oApplicationBuilder packs(MetadataPack... packs) {
        Stream.of(packs).forEach(p -> p.build(this));
        return this;
    }

    public N2oApplicationBuilder types(MetaType... types) {
        environment.getSourceTypeRegister().addAll(Arrays.asList(types));
        return this;
    }

    public N2oApplicationBuilder operations(PipelineOperation... operations) {
        environment.getPipelineOperationFactory().add(operations);
        return this;
    }

    /**
     * Добавить i/o ридеры/персистеры метаданных
     */
    @Override
    @SafeVarargs
    public final N2oApplicationBuilder ios(NamespaceIO... ios) {
        Stream.of(ios).forEach(io -> environment.getNamespaceReaderFactory().add(new ProxyNamespaceIO<>(io)));
        Stream.of(ios).forEach(io -> environment.getNamespacePersisterFactory().add(new ProxyNamespaceIO<>(io)));
        return this;
    }

    /**
     * Добавить сборщики метаданных
     */
    public N2oApplicationBuilder compilers(SourceCompiler... compilers) {
        environment.getSourceCompilerFactory().add(compilers);
        return this;
    }

    /**
     * Добавить динамические провайдеры метаданных метаданных
     */
    public N2oApplicationBuilder providers(DynamicMetadataProvider... providers) {
        environment.getDynamicMetadataProviderFactory().add(providers);
        return this;
    }

    /**
     * Добавить биндеры метаданных
     */
    public N2oApplicationBuilder binders(MetadataBinder... binders) {
        environment.getMetadataBinderFactory().add(binders);
        return this;
    }

    /**
     * Добавить сканеры метаданных
     */
    public N2oApplicationBuilder scanners(MetadataScanner... scanners) {
        environment.getMetadataScannerFactory().add(scanners);
        return this;
    }

    /**
     * Добавить лоадеры метаданных
     */
    public N2oApplicationBuilder loaders(SourceLoader... loaders) {
        environment.getSourceLoaderFactory().add(loaders);
        return this;
    }

    /**
     * Добавить маршруты получения метаданных
     */
    public N2oApplicationBuilder routes(RouteInfo... routes) {
        Stream.of(routes).forEach(
                routeInfo -> environment.getRouteRegister().addRoute(routeInfo.getUrlPattern(), routeInfo.getContext())
        );
        return this;
    }

    /**
     * Добавить информацию об исходных метаданных
     */
    public N2oApplicationBuilder sources(SourceInfo... sources) {
        Stream.of(sources).forEach(environment.getMetadataRegister()::add);
        return this;
    }

    /**
     * Добавить валидаторы метаданных
     */
    public N2oApplicationBuilder validators(SourceValidator... validators) {
        Stream.of(validators).forEach(environment.getSourceValidatorFactory()::add);
        return this;
    }

    /**
     * Добавить мержеры метаданных
     */
    public N2oApplicationBuilder mergers(SourceMerger... mergers) {
        Stream.of(mergers).forEach(environment.getSourceMergerFactory()::add);
        return this;
    }

    /**
     * Добавить трансформаторы исходных метаданных
     */
    public N2oApplicationBuilder transformers(SourceTransformer... transformers) {
        Stream.of(transformers).forEach(environment.getSourceTransformerFactory()::add);
        return this;
    }

    /**
     * Добавить трансформаторы собранных метаданных
     */
    public N2oApplicationBuilder transformers(CompileTransformer... transformers) {
        Stream.of(transformers).forEach(environment.getCompileTransformerFactory()::add);
        return this;
    }

    /**
     * Добавить преобразователи дополнительных атрибутов метаданных
     */
    public N2oApplicationBuilder extensions(ExtensionAttributeMapper... extensions) {
        Stream.of(extensions).forEach(environment.getExtensionAttributeMapperFactory()::add);
        return this;
    }

    /**
     * Добавить генераторы метаданных
     */
    public N2oApplicationBuilder generators(ButtonGenerator... generators) {
        Stream.of(generators).forEach(environment.getButtonGeneratorFactory()::add);
        return this;
    }

    /**
     * Добавить системные свойства (key=value)
     */
    public N2oApplicationBuilder properties(String... properties) {
        PropertyResolver systemProperties = environment.getSystemProperties();
        if (!(systemProperties instanceof SimplePropertyResolver))
            throw new IllegalArgumentException("System properties is readonly");
        Stream.of(properties).forEach(p -> {
            String[] split = p.contains("=") ? p.split("=", 2) : p.split(":");
            ((SimplePropertyResolver) systemProperties).setProperty(split[0], split[1]);
        });
        return this;
    }

    /**
     * Добавить файлы properties из classpath
     */
    public N2oApplicationBuilder propertySources(String... propertySources) {
        PropertyResolver systemProperties = environment.getSystemProperties();
        if (!(systemProperties instanceof SimplePropertyResolver))
            throw new IllegalArgumentException("System properties is readonly");
        Properties baseProperties = ((SimplePropertyResolver) systemProperties).getProperties();
        for (String propertySource : propertySources) {
            OverrideProperties properties = PropertiesReader.getPropertiesFromClasspath(propertySource);
            properties.setBaseProperties(baseProperties);
            baseProperties = properties;
        }
        ((N2oEnvironment) environment).setSystemProperties(new SimplePropertyResolver(baseProperties));
        return this;
    }

    /**
     * Добавить классы как отмеченные {link net.n2oapp.framework.api.metadata.global.util.ComponentType}
     */
    @SafeVarargs
    public final N2oApplicationBuilder componentTypes(Class... classes) {
        Stream.of(classes).forEach(this::addComponentType);
        return this;
    }

    /**
     * Запустить сканирование метаданных
     */
    public N2oApplicationBuilder scan() {
        build();
        List sources = environment.getMetadataScannerFactory().scan();
        environment.getMetadataRegister().addAll(sources);
        logger.info("Scanned " + sources.size() + " metadata");
        return this;
    }

    /**
     * Запустить сканирование типов метаданных
     * @param packageName Пакет для сканирования
     */
    @SuppressWarnings("unchecked")
    public void scanComponentTypes(String packageName) {
        Reflections reflections = new Reflections(packageName);
        Set> set = reflections.getTypesAnnotatedWith(ComponentType.class);
        set.forEach(clazz -> {
            Set> subTypesOf = reflections.getSubTypesOf((Class) clazz);
            subTypesOf.stream().filter(cl -> !Modifier.isAbstract(cl.getModifiers()))
                    .forEach(cl -> addComponentType((Class) cl));
        });
    }

    /**
     * Запустить конвейер чтения метаданных
     */
    @Override
    public ReadTerminalPipeline> read() {
        build();
        return N2oPipelineSupport.readPipeline(environment).read();
    }

    /**
     * Запустить конвейер сборки метаданных
     */
    @Override
    public CompileTerminalPipeline compile() {
        build();
        return N2oPipelineSupport.compilePipeline(environment).compile();
    }

    /**
     * Запустить конвейер слияния метаданных
     */
    @Override
    public CompilePipeline merge() {
        build();
        return N2oPipelineSupport.compilePipeline(environment).merge();
    }

    /**
     * Запустить конвейер связывания метаданных с данными
     */
    public BindTerminalPipeline bind() {
        build();
        return N2oPipelineSupport.bindPipeline(environment).bind();
    }

    /**
     * Запустить конвейер записи метаданных
     */
    @Override
    public PersistTerminalPipeline persist() {
        build();
        return N2oPipelineSupport.persistPipeline(environment).persist();
    }

    /**
     * Запустить конвейер десериализации метаданных
     */
    @Override
    public DeserializeTerminalPipeline deserialize() {
        build();
        return N2oPipelineSupport.deserializePipeline(environment).deserialize();
    }

    /**
     * Найти контекст метаданной по маршруту
     *
     * @param url           Адрес маршрута
     * @param compiledClass Класс собранной метаданной
     * @param params        Параметры маршрута
     * @return Контекст найденной метаданной или null
     */
    public  CompileContext route(String url, Class compiledClass, Map params) {
        build();
        return new N2oRouter(environment, read()
                .transform().validate().cache().copy()
                .compile().transform())
                .get(url, compiledClass, params);
    }

    /**
     * Получить окружение сборки метаданных
     *
     * @return Окруждение сборки метаданных
     */
    public MetadataEnvironment getEnvironment() {
        return environment;
    }

    private N2oApplicationBuilder build() {
        AwareFactorySupport.enrich(environment.getDynamicMetadataProviderFactory(), environment);
        AwareFactorySupport.enrich(environment.getMetadataScannerFactory(), environment);
        AwareFactorySupport.enrich(environment.getNamespaceReaderFactory(), environment);
        AwareFactorySupport.enrich(environment.getSourceLoaderFactory(), environment);
        AwareFactorySupport.enrich(environment.getNamespacePersisterFactory(), environment);
        AwareFactorySupport.enrich(environment.getSourceMergerFactory(), environment);
        AwareFactorySupport.enrich(environment.getSourceTransformerFactory(), environment);
        AwareFactorySupport.enrich(environment.getSourceValidatorFactory(), environment);
        AwareFactorySupport.enrich(environment.getSourceCompilerFactory(), environment);
        AwareFactorySupport.enrich(environment.getCompileTransformerFactory(), environment);
        AwareFactorySupport.enrich(environment.getMetadataBinderFactory(), environment);
        AwareFactorySupport.enrich(environment.getPipelineOperationFactory(), environment);
        return this;
    }

    private void addComponentType(Class clazz) {
        if (clazz.isAnnotationPresent(ComponentType.class)) {
            ComponentType annotation = clazz.getAnnotation(ComponentType.class);
            environment.getComponentTypeRegister()
                    .add(annotation.value() == null ? getFullClassName(clazz) : annotation.value(), clazz);
        } else {
            environment.getComponentTypeRegister().add(getFullClassName(clazz), clazz);
        }
    }

    private String getFullClassName(Class clazz) {
        return clazz.getName().substring(clazz.getName().lastIndexOf('.') + 1);
    }
}