ar.com.allium.rules.core.service.LoadAlliumRules.java Source code

Java tutorial

Introduction

Here is the source code for ar.com.allium.rules.core.service.LoadAlliumRules.java

Source

package ar.com.allium.rules.core.service;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;

import ar.com.allium.rules.core.annotation.ExecuteRule;
import ar.com.allium.rules.core.annotation.Rule;
import ar.com.allium.rules.core.annotation.AlliumRuleSet;
import ar.com.allium.rules.core.exception.AlliumRuleConfigurationException;
import ar.com.allium.rules.core.model.AlliumRule;

/**
 * Copyright 2014 Joel del Valle <joelmarcosdelvalle@gmail.com>
 * 
 * This file is part of allium-rules, project of allium-projects.
 * 
 * allium-rules 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.
 * 
 * allium-rules 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
 * allium-rules. If not, see <http://www.gnu.org/licenses/>.
 * 
 * 
 * @author joel.delvalle
 * 
 *         service to load and build rules or set of rules
 * 
 */
@SuppressWarnings("rawtypes")
public final class LoadAlliumRules {

    private static Logger log = Logger.getLogger(LoadAlliumRules.class);

    private static final String EMPTY_STRING = "";

    private static final String ALLIUM_CORE_RULE_PACKAGE = "/ar/com/allium/rules/core";

    private AlliumCoreRuleManager alliumRuleCore;

    private String basePackage;

    private ApplicationContext springContext;

    private List<AlliumRule> alliumRuleList;

    private List<Class<?>> clazzWithMethodThatAlliumRulesImplement;

    public LoadAlliumRules(ApplicationContext springContext) {
        this.basePackage = EMPTY_STRING;
        this.springContext = springContext;
        this.alliumRuleList = new ArrayList<AlliumRule>();
        this.clazzWithMethodThatAlliumRulesImplement = new ArrayList<Class<?>>();
    }

    public LoadAlliumRules(String basePackage, WebApplicationContext springContext) {

        if (basePackage.endsWith(".")) {
            basePackage = basePackage.substring(0, basePackage.length() - 1);
        }

        if (basePackage.endsWith(".*")) {
            basePackage = basePackage.substring(0, basePackage.length() - 2);
        }

        this.basePackage = basePackage;
        this.springContext = springContext;
        this.alliumRuleList = new ArrayList<AlliumRule>();
        this.clazzWithMethodThatAlliumRulesImplement = new ArrayList<Class<?>>();
    }

    public void loadAlliumRules() {

        log.debug("Load and Build AlliumRule");

        this.loadAlliumRule();

        log.debug("Total found " + alliumRuleList.size() + " AlliumRule");

        this.buildRulesMap();

        log.debug("Validate AlliumRule used");

        this.validateExcuteRuleAnnotationParameters();
    }

    private void validateExcuteRuleAnnotationParameters() {
        log.debug("Found " + this.clazzWithMethodThatAlliumRulesImplement.size()
                + " class with AlliumRule implementation");

        for (Class<?> clazz : this.clazzWithMethodThatAlliumRulesImplement) {

            for (Method method : clazz.getMethods()) {

                ExecuteRule executeRuleAnnotation = method.getAnnotation(ExecuteRule.class);

                if (executeRuleAnnotation != null) {

                    if (executeRuleAnnotation.ruleClass().length == 0
                            && executeRuleAnnotation.ruleSetName().length == 0) {
                        throw new AlliumRuleConfigurationException(
                                "Found error in ExecuteRule configuration. The method '" + method.getName()
                                        + "' in class " + clazz.getCanonicalName()
                                        + " has not properly declared annotation @ExecuteRule. Remember to declare a 'ruleClass' or 'ruleSetName'");
                    }
                }
            }
        }
    }

    private void buildRulesMap() {

        for (AlliumRule alliumRule : alliumRuleList) {

            AlliumRuleSet alliumRuleSet = alliumRule.getClass().getAnnotation(AlliumRuleSet.class);

            if (alliumRuleSet != null) {

                for (String setName : alliumRuleSet.alliumRuleSetNames()) {

                    if (setName != null && setName.trim() != EMPTY_STRING) {
                        getAlliumCoreRuleManager().addRule(setName, alliumRule);
                    }

                }

            } else {

                getAlliumCoreRuleManager().addRule(alliumRule);

            }
        }
    }

    @SuppressWarnings("unchecked")
    private void loadAlliumRule() {

        Class[] classes = this.getClassesInPackage(this.basePackage, Rule.class);
        for (Class c : classes) {

            AlliumRule newInstance;

            try {
                newInstance = (AlliumRule) springContext.getBean(c);
            } catch (NoSuchBeanDefinitionException noBean) {
                try {
                    newInstance = (AlliumRule) c.newInstance();
                } catch (Exception e) {
                    throw new AlliumRuleConfigurationException("Error to create AlliumRule", e);
                }

            }

            log.debug("   " + newInstance.getClass().getCanonicalName());
            alliumRuleList.add(newInstance);
        }
    }

    private Class[] getClassesInPackage(String basePackage, Class<?> classType) {

        File directory = this.getPackageDirectory(basePackage);

        if (!directory.exists()) {
            throw new AlliumRuleConfigurationException(
                    "Could not get directory resource for package " + basePackage + ".");
        }

        return this.getClassesInPackage(basePackage, directory, classType);
    }

    private File getPackageDirectory(String basePackage) {

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        if (classLoader == null) {
            throw new AlliumRuleConfigurationException("Can't get class loader.");
        }

        URL resource = classLoader.getResource(basePackage.replace('.', '/'));
        if (resource == null) {
            throw new AlliumRuleConfigurationException("Package " + basePackage + " not found on classpath.");
        }

        return new File(resource.getFile());
    }

    @SuppressWarnings("unchecked")
    private Class[] getClassesInPackage(String basePackage, File directory, Class classType) {

        List<String> className = new ArrayList<String>();
        this.findAllClassInPackage(directory.getAbsolutePath(), directory, className);

        List<Class> classes = new ArrayList<Class>();

        for (String filename : className) {

            if (filename.endsWith(".class")) {
                String classname = this.buildClassname(basePackage, filename);
                try {

                    Class<?> clazz = Class.forName(classname);

                    if (clazz.getSuperclass() != null && clazz.getSuperclass().getCanonicalName()
                            .equals(AlliumRule.class.getCanonicalName())) {

                        if (clazz.getSuperclass().getAnnotation(classType) != null) {
                            classes.add(clazz);
                        }
                    }

                    if (this.haveAnyMethodWithAlliumRuleImplementation(clazz)) {
                        this.clazzWithMethodThatAlliumRulesImplement.add(clazz);
                    }

                } catch (ClassNotFoundException e) {
                    log.error("Error creating class " + classname);
                }
            }

        }

        return classes.toArray(new Class[classes.size()]);
    }

    private boolean haveAnyMethodWithAlliumRuleImplementation(Class<?> clazz) {

        for (Method method : clazz.getMethods()) {
            if (method.getAnnotation(ExecuteRule.class) != null) {
                return true;
            }
        }

        return false;
    }

    private void findAllClassInPackage(String baseDirectory, File file, List<String> all) {

        try {

            File[] children = file.listFiles();

            if (children != null) {
                for (File child : children) {
                    if (!child.isDirectory() && !this.invalidDirecory(baseDirectory, file.getCanonicalPath())) {
                        all.add(child.getAbsolutePath().substring(baseDirectory.length()));
                    }
                    findAllClassInPackage(baseDirectory, child, all);
                }
            }

        } catch (IOException ioe) {
            throw new AlliumRuleConfigurationException("Error to find AlliumRule");
        }
    }

    private String buildClassname(String pckgname, String filename) {
        String classPath = pckgname + filename.replace(".class", "").replace("/", ".");

        if (classPath.startsWith(".")) {
            classPath = classPath.substring(1);
        }

        return classPath;
    }

    private boolean invalidDirecory(String baseDirectory, String filePath) {

        filePath = filePath.substring(baseDirectory.length());

        return filePath.startsWith(ALLIUM_CORE_RULE_PACKAGE);
    }

    private AlliumCoreRuleManager getAlliumCoreRuleManager() {
        if (alliumRuleCore == null) {
            alliumRuleCore = springContext.getBean("alliumCoreRuleManager", AlliumCoreRuleManager.class);
        }
        return alliumRuleCore;
    }

}