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

fr.ird.observe.maven.plugins.toolbox.ValidatorsCache Maven / Gradle / Ivy

package fr.ird.observe.maven.plugins.toolbox;

/*-
 * #%L
 * ObServe Toolkit :: Maven plugin
 * %%
 * Copyright (C) 2008 - 2018 IRD, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
import java.util.EnumSet;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import org.apache.maven.plugin.logging.Log;
import org.nuiton.validator.NuitonValidatorScope;
import org.nuiton.validator.bean.simple.SimpleBeanValidator;

/**
 * Created on 31/08/16.
 *
 * @author Tony Chemit - [email protected]
 */
public class ValidatorsCache {

    public static class ValidatorInfo {

        private final Class type;
        private final String context;
        private final NuitonValidatorScope scope;
        private final Set fields;

        ValidatorInfo(Class type, String context, NuitonValidatorScope scope, Set fields) {
            this.type = type;
            this.context = context;
            this.scope = scope;
            this.fields = fields;
        }

        public Class getType() {
            return type;
        }

        public String getContext() {
            return context;
        }

        public NuitonValidatorScope getScope() {
            return scope;
        }

        public Set getFields() {
            return fields;
        }
    }

    private final static ValidatorsCache instance = new ValidatorsCache();

    public static ValidatorsCache get() {
        return instance;
    }

    private final Multimap validators = ArrayListMultimap.create();

    public Collection getValidators(ValidatorCacheRequest request) throws IOException {

        Log log = request.getLog();
        boolean verbose = request.isVerbose();
        Path sourceRootPath = request.getSourceRootPath();

        String key = sourceRootPath.toFile().getAbsolutePath();
        if (!validators.containsKey(key)) {

            log.info("Loading validators from " + sourceRootPath);

            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
            try {

                Thread.currentThread().setContextClassLoader(request.getUrlClassLoader());

                PathSimpleFileVisitorResult result = new PathSimpleFileVisitor(log, sourceRootPath, verbose).walk();

                NuitonValidatorScope[] scopes = result.getEffectiveScopes();

                for (ValidatorDescriptor descritptor : result.descritptors) {

                    String typeName = descritptor.getTypeName();
                    String context = descritptor.getContext();

                    Class type = Class.forName(typeName);

                    SimpleBeanValidator validator = SimpleBeanValidator.newValidator(type, context, scopes);
                    for (NuitonValidatorScope scope : validator.getEffectiveScopes()) {

                        Set effectiveFields = validator.getEffectiveFields(scope);
                        ValidatorInfo validatorInfo = new ValidatorInfo(type, context, scope, effectiveFields);
                        validators.put(key, validatorInfo);
                    }


                }

            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e);
            } finally {

                Thread.currentThread().setContextClassLoader(contextClassLoader);

            }

        }
        return validators.get(key);
    }


    private static class PathSimpleFileVisitorResult {

        private final Set descritptors;

        private PathSimpleFileVisitorResult(Set descritptors) {
            this.descritptors = descritptors;
        }


        public NuitonValidatorScope[] getEffectiveScopes() {

            EnumSet result = EnumSet.noneOf(NuitonValidatorScope.class);
            result.addAll(descritptors.stream().map(ValidatorDescriptor::getScope).collect(Collectors.toList()));
            return result.toArray(new NuitonValidatorScope[0]);
        }

    }

    private static class ValidatorDescriptor {

        private final String typeName;
        private final String context;
        private final NuitonValidatorScope scope;

        private ValidatorDescriptor(String typeName, String context, NuitonValidatorScope scope) {
            this.typeName = typeName;
            this.context = context;
            this.scope = scope;
        }

        public String getTypeName() {
            return typeName;
        }

        public String getContext() {
            return context;
        }

        public NuitonValidatorScope getScope() {
            return scope;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ValidatorDescriptor that = (ValidatorDescriptor) o;
            return Objects.equals(getTypeName(), that.getTypeName()) &&
                    Objects.equals(getContext(), that.getContext()) &&
                    getScope() == that.getScope();
        }

        @Override
        public int hashCode() {
            return Objects.hash(getTypeName(), getContext(), getScope());
        }
    }

    private static class PathSimpleFileVisitor extends SimpleFileVisitor {

        private final Set descritptors = new LinkedHashSet<>();
        private final Set scopes = new LinkedHashSet<>();
        private final Log log;
        private final Path sourceRootPath;
        private final boolean verbose;

        private String packageName = "";

        PathSimpleFileVisitor(Log log, Path sourceRootPath, boolean verbose) {

            this.log = log;
            this.sourceRootPath = sourceRootPath;
            this.verbose = verbose;

            for (NuitonValidatorScope scope : NuitonValidatorScope.values()) {
                scopes.add(scope.name().toLowerCase());
            }
        }

        public PathSimpleFileVisitorResult walk() throws IOException {

            Files.walkFileTree(sourceRootPath, this);

            log.info(descritptors.size() + " type(s) detected.");
            return new PathSimpleFileVisitorResult(descritptors);
        }

        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
            if (!dir.equals(sourceRootPath)) {
                if (!packageName.isEmpty()) {
                    packageName += ".";
                }
                packageName += dir.toFile().getName();
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
            if (!dir.equals(sourceRootPath)) {
                String name = dir.toFile().getName();
                packageName = packageName.substring(0, packageName.length() - name.length());
                if (packageName.endsWith(".")) {
                    packageName = packageName.substring(0, packageName.length() - 1);
                }
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
            String name = file.toFile().getName();
            if (name.endsWith("-validation.xml")) {
                int i = name.indexOf('-');
                String typeName = packageName + "." + name.substring(0, i);
                String rest = name.substring(i);
                LinkedHashSet contexts = new LinkedHashSet<>();
                StringTokenizer tok = new StringTokenizer(rest, "-");
                NuitonValidatorScope scope = null;
                while (tok.hasMoreTokens()) {

                    String token = tok.nextToken();
                    if (scopes.contains(token)) {
                        scope = NuitonValidatorScope.valueOf(token.toUpperCase());
                        break;
                    }
                    contexts.add(token);
                }
                String context = String.join("-", contexts);
                ValidatorDescriptor descritptor = new ValidatorDescriptor(typeName, context, scope);

                boolean add = descritptors.add(descritptor);
                if (add) {
                    if (verbose) {
                        log.info("Register " + typeName);
                    }
                }
            }
            return FileVisitResult.CONTINUE;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy