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

jaxx.runtime.validator.BeanValidatorDetector Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * *##% 
 * JAXX Runtime
 * Copyright (C) 2008 - 2009 CodeLutin
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * ##%*
 */
package jaxx.runtime.validator;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Un detecteur de validateurs pour un liste de classes données et un
 * répertoire où chercher les fichiers de validation.
 * 
 * @author chemit
 *
 * @since 1.6.0
 */
public class BeanValidatorDetector {

    /** to use log facility, just put in your code: log.info(\"...\"); */
    private static final Log log = LogFactory.getLog(BeanValidatorDetector.class);

    public SortedSet> detect(File sourceRoot, Class... types) {
        SortedSet> result = detect(BeanValidator.class, sourceRoot, null, types);
        return result;
    }

    public SortedSet> detect(Class validatorClass, File sourceRoot, Pattern contextFilter, Class... types) {

        SortedSet> result = new TreeSet>(new BeanValidatorComparator());

        for (Class c : types) {
            File dir = getClassDir(sourceRoot, c);
            if (!dir.exists()) {
                // pas de repertoire adequate
                log.debug("skip non existing directory " + dir);
                continue;
            }
            String[] contexts = getContexts(c, dir);
            if (log.isDebugEnabled()) {
                log.debug("contexts : " + Arrays.toString(contexts));
            }

            if (contexts.length > 0) {
                String[] realContexts = getContextsWithoutScopes(contexts);

                if (log.isDebugEnabled()) {
                    log.debug("realContexts : " + Arrays.toString(realContexts));
                }

                if (contextFilter != null) {
                    // filter contexts
                    realContexts = getFilterContexts(contextFilter, realContexts);
                    if (log.isDebugEnabled()) {
                        log.debug("filterContexts : " + Arrays.toString(realContexts));
                    }
                }

                for (String context : realContexts) {

                    // on cherche le validateur
                    BeanValidator validator = getValidator(validatorClass, c, context.isEmpty() ? null : context);
                    if (validator != null) {
                        // on enregistre le validateur
                        result.add(validator);
                    }
                }
            }
        }
        return result;
    }

    /**
     * Pour un context et un type d'entité donné, instancie un validateur
     * et test si ce validateur est utilisable (i.e qu'il admet des champs
     * à valider).
     *
     * Si aucun champ n'est trouvé dans le validateur, alors on retourne null.
     *
     * @param  le type du bean
     * @param validatorClass le type de validateur a instancie
     * @param klass le type du bean
     * @param context le context du validateur
     * @return le validateur initialisé, ou null si aucun scope
     *         détecté dans le validateur.
     */
    protected  BeanValidator getValidator(Class validatorClass, Class klass, String context) {

//        BeanValidator valitator = new BeanValidator(klass, context);
        BeanValidator valitator;
        try {
            valitator = (BeanValidator) validatorClass.getConstructor(Class.class, String.class).newInstance(klass, context);
        } catch (Exception ex) {
            throw new RuntimeException("could not instanciate validator " + validatorClass + " for reason " + ex.getMessage(), ex);
        }

        Set scopes = valitator.getScopes();
        if (scopes.isEmpty()) {
            valitator = null;
            if (log.isDebugEnabled()) {
                log.debug(klass + " : validator skip (no scopes detected)");
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug(klass + " : keep validator " + valitator);
            }
        }
        return valitator;
    }

    protected File getClassDir(File sourceRoot, Class clazz) {
        String path = clazz.getPackage().getName().replaceAll("\\.", File.separator);
        File dir = new File(sourceRoot, path);
        return dir;
    }

    protected String[] getContexts(Class clazz, File dir) {
        Set result = new TreeSet();
        ValidatorFilenameFilter filter = new ValidatorFilenameFilter(clazz);
        if (log.isDebugEnabled()) {
            log.debug("dir : " + dir);
        }
        String[] files = dir.list(filter);
        for (String file : files) {
            if (log.isDebugEnabled()) {
                log.debug("file " + file);
            }
            String context = file.substring(filter.prefix.length(), file.length() - ValidatorFilenameFilter.SUFFIX.length());
            if (log.isDebugEnabled()) {
                log.debug("detect " + clazz.getSimpleName() + " context [" + context + "]");
            }
            result.add(context);
        }
        return result.toArray(new String[result.size()]);
    }

    protected String[] getContextsWithoutScopes(String[] contexts) {
        Set result = new TreeSet();
        BeanValidatorScope[] scopes = BeanValidatorScope.values();
        for (String context : contexts) {
            for (BeanValidatorScope scope : scopes) {
                String scopeName = scope.name().toLowerCase();
                if (!context.endsWith(scopeName)) {
                    // pas concerne par ce scope
                    continue;
                }
                if (log.isDebugEnabled()) {
                    log.debug("detect context : " + context);
                }
                String realContext = context.substring(0, context.length() - scopeName.length());
                if (realContext.endsWith("-")) {
                    realContext = realContext.substring(0, realContext.length() - 1);
                }
                result.add(realContext);
            }
        }
        return result.toArray(new String[result.size()]);
    }

    protected String[] getFilterContexts(Pattern contextFilter, String[] realContexts) {
        List result = new ArrayList();
        for (String c : realContexts) {
            Matcher m = contextFilter.matcher(c);
            if (m.matches()) {
                result.add(c);
            }
        }
        return result.toArray(new String[result.size()]);
    }

    protected static class ValidatorFilenameFilter implements FilenameFilter {

        protected static final String SUFFIX = "-validation.xml";
        protected Class clazz;
        protected String prefix;

        public ValidatorFilenameFilter(Class clazz) {
            this.clazz = clazz;
            this.prefix = clazz.getSimpleName() + "-";
        }

        @Override
        public boolean accept(File dir, String name) {
            boolean result = name.endsWith(SUFFIX);
            if (result) {
                result = name.startsWith(prefix);
            }
            return result;
        }
    }

    protected static class BeanValidatorComparator implements Comparator> {

        @Override
        public int compare(BeanValidator o1, BeanValidator o2) {
            String contextName1 = o1.getBeanClass().getSimpleName() + "-" + (o1.getContextName() == null ? "" : o1.getContextName());
            String contextName2 = o2.getBeanClass().getSimpleName() + "-" + (o2.getContextName() == null ? "" : o2.getContextName());
            return contextName1.compareTo(contextName2);
        }
    }
}