com.jsmartframework.web.manager.BeanHelper.java Source code

Java tutorial

Introduction

Here is the source code for com.jsmartframework.web.manager.BeanHelper.java

Source

/*
 * JSmart Framework - Java Web Development Framework
 * Copyright (c) 2015, Jeferson Albino da Silva, All rights reserved.
 *
 * This library 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.0 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

package com.jsmartframework.web.manager;

import static com.jsmartframework.web.config.Config.CONFIG;

import com.google.gson.internal.Primitives;
import com.jsmartframework.web.annotation.AuthAccess;
import com.jsmartframework.web.annotation.AuthBean;
import com.jsmartframework.web.annotation.AuthField;
import com.jsmartframework.web.annotation.AuthMethod;
import com.jsmartframework.web.annotation.ExecuteAccess;
import com.jsmartframework.web.annotation.ExposeVar;
import com.jsmartframework.web.annotation.PostAction;
import com.jsmartframework.web.annotation.PostSubmit;
import com.jsmartframework.web.annotation.PreAction;
import com.jsmartframework.web.annotation.PreSet;
import com.jsmartframework.web.annotation.PreSubmit;
import com.jsmartframework.web.annotation.Unescape;
import com.jsmartframework.web.annotation.VarMapping;
import com.jsmartframework.web.annotation.WebBean;
import com.jsmartframework.web.annotation.WebFilter;
import com.jsmartframework.web.annotation.WebSecurity;
import com.jsmartframework.web.annotation.WebServlet;
import com.jsmartframework.web.config.UrlPattern;

import com.jsmartframework.web.util.WebText;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

enum BeanHelper {

    HELPER();

    private static final String ENCODING = "UTF-8";

    private static final Logger LOGGER = Logger.getLogger(BeanHelper.class.getPackage().getName());

    private static final Pattern SET_METHOD_PATTERN = Pattern.compile("^set(.*)");

    private static final Pattern PROPERTIES_NAME_PATTERN = Pattern.compile("\\s*_(.*)\\.properties");

    private static final Pattern PATH_BEAN_ALL_PATTERN = Pattern.compile("(.*)/\\*");

    private Map<Class<?>, String> beanNames = new ConcurrentHashMap<>();

    private Map<Class<?>, Field[]> beanFields = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> beanMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Field[]> preSetFields = new ConcurrentHashMap<>();

    private Map<Class<?>, Field[]> exposeVarFields = new ConcurrentHashMap<>();

    private Map<String, List<Class<?>>> exposeVarPaths = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> postConstructMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> preDestroyMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> preSubmitMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> preActionMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> postSubmitMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> postActionMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, String[]> unescapeMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> executeAccessMethods = new ConcurrentHashMap<>();

    private Map<Class<?>, Field[]> authFields = new ConcurrentHashMap<>();

    private Map<Class<?>, Field[]> authAccess = new ConcurrentHashMap<>();

    private Map<Class<?>, Method[]> authMethods = new ConcurrentHashMap<>();

    private Map<Field, Map<String, WebText.WebTextSet>> varMappingFields = new ConcurrentHashMap<>();

    String getBeanName(Class<?> clazz) {
        return beanNames.get(clazz);
    }

    String getClassName(String name) {
        return name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toLowerCase());
    }

    String getClassName(WebBean webBean, Class<?> beanClass) {
        String beanName = webBean.name();
        if (StringUtils.isBlank(beanName)) {
            beanName = getClassName(beanClass.getSimpleName());
        }
        beanNames.put(beanClass, beanName);
        return beanName;
    }

    String getClassName(AuthBean authBean, Class<?> authClass) {
        String beanName = authBean.name();
        if (StringUtils.isBlank(beanName)) {
            beanName = getClassName(authClass.getSimpleName());
        }
        beanNames.put(authClass, beanName);
        return beanName;
    }

    String getClassName(WebServlet servlet, Class<?> servletClass) {
        if (StringUtils.isBlank(servlet.name())) {
            String servletName = servletClass.getSimpleName();
            return getClassName(servletName);
        }
        return servlet.name();
    }

    String getClassName(WebFilter filter, Class<?> filterClass) {
        if (StringUtils.isBlank(filter.name())) {
            String filterName = filterClass.getSimpleName();
            return getClassName(filterName);
        }
        return filter.name();
    }

    String getClassName(WebSecurity security, Class<?> securityClass) {
        String securityName = securityClass.getSimpleName();
        return getClassName(securityName);
    }

    Field[] getBeanFields(Class<?> clazz) {
        if (!beanFields.containsKey(clazz)) {
            beanFields.put(clazz, getAllDeclaredFields(clazz));
        }
        return beanFields.get(clazz);
    }

    void setBeanFields(Class<?> clazz) {
        if (!beanFields.containsKey(clazz)) {

            List<Field> preSets = new ArrayList<>();
            List<Field> exposeVars = new ArrayList<>();

            for (Field field : getAllDeclaredFields(clazz)) {
                field.setAccessible(true);
                if (field.isAnnotationPresent(PreSet.class)) {
                    preSets.add(field);
                }

                if (field.isAnnotationPresent(ExposeVar.class)) {
                    exposeVars.add(field);
                    ExposeVar exposeVar = field.getAnnotation(ExposeVar.class);

                    if (StringUtils.isNotBlank(exposeVar.value().i18n())) {
                        if (!field.getType().equals(Map.class)) {
                            throw new RuntimeException("Field [" + field + "] annotated with ExposeVar containing "
                                    + "VarMapping attribute must be the type of Map<String, Object>");
                        }
                        setExposeVarMapping(field, exposeVar.value());
                    }

                    for (String varPath : cleanPaths(exposeVar.forPaths())) {
                        List<Class<?>> classes = exposeVarPaths.get(varPath);
                        if (classes == null) {
                            exposeVarPaths.put(varPath, classes = new ArrayList<>());
                        }
                        classes.add(clazz);
                    }
                }
            }

            beanFields.put(clazz, getAllDeclaredFields(clazz));
            preSetFields.put(clazz, preSets.toArray(new Field[preSets.size()]));
            exposeVarFields.put(clazz, exposeVars.toArray(new Field[exposeVars.size()]));
        }
    }

    private Field[] getAllDeclaredFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        Class<?> superClazz = clazz;
        while (superClazz != null && superClazz != Object.class) {
            fields.addAll(Arrays.asList(superClazz.getDeclaredFields()));
            superClazz = superClazz.getSuperclass();
        }
        return fields.toArray(new Field[fields.size()]);
    }

    Field[] getPreSetFields(Class<?> clazz) {
        Field[] fields = preSetFields.get(clazz);
        return fields != null ? fields : new Field[] {};
    }

    String[] getUnescapeMethods(Class<?> clazz) {
        String[] methods = unescapeMethods.get(clazz);
        return methods != null ? methods : new String[] {};
    }

    Method[] getPostConstructMethods(Class<?> clazz) {
        Method[] methods = postConstructMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    Method[] getPreDestroyMethods(Class<?> clazz) {
        Method[] methods = preDestroyMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    @Deprecated
    Method[] getPostSubmitMethods(Class<?> clazz) {
        Method[] methods = postSubmitMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    Method[] getPostActionMethods(Class<?> clazz) {
        Method[] methods = postActionMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    @Deprecated
    Method[] getPreSubmitMethods(Class<?> clazz) {
        Method[] methods = preSubmitMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    Method[] getPreActionMethods(Class<?> clazz) {
        Method[] methods = preActionMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    Method[] getExecuteAccessMethods(Class<?> clazz) {
        Method[] methods = executeAccessMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    Method[] getBeanMethods(Class<?> clazz) {
        if (!beanMethods.containsKey(clazz)) {
            beanMethods.put(clazz, clazz.getMethods());
        }
        return beanMethods.get(clazz);
    }

    void setBeanMethods(Class<?> clazz) {
        if (!beanMethods.containsKey(clazz)) {
            List<Method> postConstructs = new ArrayList<>();
            List<Method> preDestroys = new ArrayList<>();
            List<Method> postSubmits = new ArrayList<>();
            List<Method> postActions = new ArrayList<>();
            List<Method> preSubmits = new ArrayList<>();
            List<Method> preActions = new ArrayList<>();
            List<String> unescapes = new ArrayList<>();
            List<Method> executeAccess = new ArrayList<>();

            for (Method method : clazz.getMethods()) {
                if (method.isAnnotationPresent(PostConstruct.class)) {
                    postConstructs.add(method);
                }
                if (method.isAnnotationPresent(PreDestroy.class)) {
                    preDestroys.add(method);
                }
                if (method.isAnnotationPresent(PostSubmit.class)) {
                    postSubmits.add(method);
                }
                if (method.isAnnotationPresent(PostAction.class)) {
                    postActions.add(method);
                }
                if (method.isAnnotationPresent(PreSubmit.class)) {
                    preSubmits.add(method);
                }
                if (method.isAnnotationPresent(PreAction.class)) {
                    preActions.add(method);
                }
                if (method.isAnnotationPresent(Unescape.class)) {
                    Matcher matcher = SET_METHOD_PATTERN.matcher(method.getName());
                    if (matcher.find()) {
                        unescapes.add(matcher.group(1));
                    }
                }
                if (method.isAnnotationPresent(ExecuteAccess.class)) {
                    executeAccess.add(method);
                }
            }

            beanMethods.put(clazz, clazz.getMethods());
            executeAccessMethods.put(clazz, executeAccess.toArray(new Method[executeAccess.size()]));
            postConstructMethods.put(clazz, postConstructs.toArray(new Method[postConstructs.size()]));
            preDestroyMethods.put(clazz, preDestroys.toArray(new Method[preDestroys.size()]));
            postSubmitMethods.put(clazz, postSubmits.toArray(new Method[postSubmits.size()]));
            postActionMethods.put(clazz, postActions.toArray(new Method[postActions.size()]));
            preSubmitMethods.put(clazz, preSubmits.toArray(new Method[preSubmits.size()]));
            preActionMethods.put(clazz, preActions.toArray(new Method[preActions.size()]));
            unescapeMethods.put(clazz, unescapes.toArray(new String[unescapes.size()]));
        }
    }

    Field[] getAuthFields(Class<?> clazz) {
        Field[] fields = authFields.get(clazz);
        return fields != null ? fields : new Field[] {};
    }

    boolean hasPrimitiveAuthFields(Class<?> clazz) {
        Field[] fields = getAuthFields(clazz);
        for (int i = 0; i < fields.length; i++) {
            if (Primitives.isPrimitive(fields[i].getGenericType())) {
                return true;
            }
        }
        return false;
    }

    void setAuthFields(Class<?> clazz) {
        if (!authFields.containsKey(clazz)) {
            List<Field> fields = new ArrayList<>();

            for (Field field : getBeanFields(clazz)) {
                if (!field.isAnnotationPresent(AuthField.class)) {
                    continue;
                }
                fields.add(field);
            }
            authFields.put(clazz, fields.toArray(new Field[fields.size()]));
        }
    }

    Field[] getAuthAccess(Class<?> clazz) {
        Field[] fields = authAccess.get(clazz);
        return fields != null ? fields : new Field[] {};
    }

    void setAuthAccess(Class<?> clazz) {
        if (!authAccess.containsKey(clazz)) {
            List<Field> fields = new ArrayList<>();

            for (Field field : getBeanFields(clazz)) {
                if (!field.isAnnotationPresent(AuthAccess.class)) {
                    continue;
                }
                fields.add(field);
            }
            authAccess.put(clazz, fields.toArray(new Field[fields.size()]));
        }
    }

    Method[] getAuthMethods(Class<?> clazz) {
        Method[] methods = authMethods.get(clazz);
        return methods != null ? methods : new Method[] {};
    }

    void setAuthMethods(Class<?> clazz) {
        if (!authMethods.containsKey(clazz)) {
            List<Method> methods = new ArrayList<>();

            for (Method method : getBeanMethods(clazz)) {
                if (!method.isAnnotationPresent(AuthMethod.class)) {
                    continue;
                }
                Class<?> returnType = method.getReturnType();
                if (Boolean.class == returnType || boolean.class == returnType) {
                    methods.add(method);
                }
            }
            authMethods.put(clazz, methods.toArray(new Method[methods.size()]));
        }
    }

    List<String> cleanPaths(String[] urlPaths) {
        List<String> cleanPaths = new ArrayList<>();
        if (urlPaths.length == 1 && "/*".equals(urlPaths[0].trim())) {
            urlPaths = CONFIG.getContent().getUrlPatternsArray();
        }

        for (String urlPattern : urlPaths) {
            String path = getCleanPath(urlPattern);
            cleanPaths.add(matchUrlPattern(path));
        }
        return cleanPaths;
    }

    String getCleanPath(String path) {
        Matcher matcher = PATH_BEAN_ALL_PATTERN.matcher(path);
        if (matcher.find()) {
            path = matcher.group(1);
        }
        return path;
    }

    String matchUrlPattern(String path) {
        for (UrlPattern urlPattern : CONFIG.getContent().getUrlPatterns()) {
            if (urlPattern.getUrl().equals(path)) {
                return urlPattern.getUrl();
            }
        }
        for (UrlPattern urlPattern : CONFIG.getContent().getUrlPatterns()) {
            if (urlPattern.getUrl().contains("/*")) {
                String url = urlPattern.getUrl().replace("/*", "");
                if (path.equals(url)) {
                    return url;
                }
            }
        }
        return path;
    }

    Field[] getExposeVarFields(Class<?> clazz) {
        Field[] fields = exposeVarFields.get(clazz);
        return fields != null ? fields : new Field[] {};
    }

    List<Class<?>> getExposeVarByPath(String path) {
        List<Class<?>> classes = exposeVarPaths.get(path);
        return classes != null ? classes : Collections.EMPTY_LIST;
    }

    Map<String, Object> getExposeVarMapping(Field field) {
        Locale locale = WebContext.getLocale();
        String language = locale != null ? locale.getLanguage() : Locale.getDefault().getLanguage();

        Map<String, WebText.WebTextSet> localeTexts = varMappingFields.get(field);
        if (localeTexts != null) {
            if (localeTexts.containsKey(language)) {
                return localeTexts.get(language).getValues();
            }
            return localeTexts.get(Locale.getDefault().getLanguage()).getValues();
        }
        return null;
    }

    private void setExposeVarMapping(Field field, VarMapping varMapping) {
        try {
            List<String> properties = IOUtils.readLines(getClass().getClassLoader().getResourceAsStream("/"),
                    ENCODING);
            for (String propertiesName : properties) {

                if (propertiesName.startsWith(varMapping.i18n()) && propertiesName.endsWith(".properties")) {
                    String language = CONFIG.getContent().getDefaultLanguage();

                    Matcher matcher = PROPERTIES_NAME_PATTERN.matcher(propertiesName);
                    if (matcher.find()) {
                        language = matcher.group(1);
                    }
                    setExposeVarMapping(field, varMapping, language);
                }
            }
            setExposeVarMapping(field, varMapping, Locale.getDefault().getLanguage());

        } catch (IOException ex) {
            LOGGER.log(Level.SEVERE, "Error reading list of resource properties", ex);
        }
    }

    private void setExposeVarMapping(Field field, VarMapping varMapping, String language) {
        WebText.WebTextSet webTextSet = WebText.getStrings(varMapping.i18n(), varMapping.prefix(), language);

        if (webTextSet != null) {
            Map<String, WebText.WebTextSet> localeTexts = varMappingFields.get(field);
            if (localeTexts == null) {
                varMappingFields.put(field, localeTexts = new ConcurrentHashMap<>());
            }
            localeTexts.put(webTextSet.getLanguage(), webTextSet);
        }
    }
}