Package com.bastengao.struts2.freeroute

Source Code of com.bastengao.struts2.freeroute.ControllerPackageProvider

package com.bastengao.struts2.freeroute;

import com.bastengao.struts2.freeroute.annotation.ContentBase;
import com.bastengao.struts2.freeroute.annotation.MethodType;
import com.bastengao.struts2.freeroute.annotation.Route;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.google.common.reflect.ClassPath;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.PackageProvider;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.PackageConfig;
import com.opensymphony.xwork2.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;


/**
* 对 controller 进行扫描,并对其进行配置(PackageConfig, ActionConfig)
*
* @author bastengao
* @date 12-12-16 13:56
* @since 1.0
*/
public class ControllerPackageProvider implements PackageProvider {
    private static final Logger log = LoggerFactory.getLogger(ControllerPackageProvider.class);
    // package name prefix
    public static final String FREEROUTE_DEFAULT = "freeroute-default#";

    private Configuration configuration;
    private RouteMappingHandler routeMappingHandler;

    // controller 所在的包
    private String controllerPackage;

    // controller 后缀
    private Set<String> controllerSuffixes;

    // 默认父包 (如果没有配置,默认为 "struts-default")
    private String defaultParentPackage;


    // 是否 struts2-spring-plugin 被加载, 如果存在将 action class name 转换为 spring bean name
    private boolean hasSpringPlugin = false;

    @Inject("routeMappingHandler")
    private void setRouteMappingHandler(RouteMappingHandler routeMappingHandler) {
        log.trace("routeMappingHandler:{}", routeMappingHandler);
        this.routeMappingHandler = routeMappingHandler;
    }

    @Inject(value = "struts.freeroute.controllerPackage", required = true)
    private void setControllerPackage(String controllerPackage) {
        this.controllerPackage = controllerPackage;
    }

    @Inject(value = "struts.freeroute.controllerSuffixes", required = true)
    private void setControllerSuffixes(String controllerSuffixes) {

        Splitter splitter = Splitter.on(",").trimResults().omitEmptyStrings();
        this.controllerSuffixes = Sets.newHashSet(splitter.split(controllerSuffixes));
    }

    @Inject(value = "struts.freeroute.defaultParentPackage", required = true)
    private void setDefaultParentPackage(String defaultParentPackage) {
        this.defaultParentPackage = defaultParentPackage;
    }

    /**
     * 注意,如果不存在 struts2-spring-plugin 那么此方法不会被调用
     *
     * @param objectFactory
     */
    @Inject(value = "spring", required = false)
    private void setStrutsSpringObjectFactory(ObjectFactory objectFactory) {
        hasSpringPlugin = true;
    }

    @Override
    public void init(Configuration configuration) throws ConfigurationException {
        log.debug("init");
        log.debug("struts2-spring-plugin: {}", hasSpringPlugin);
        this.configuration = configuration;
    }

    @Override
    public boolean needsReload() {
        log.debug("needsReload:false");
        return false;
    }

    @Override
    public void loadPackages() throws ConfigurationException {
        log.debug("loadPackages");

        Map<String, PackageConfig.Builder> packages = createPackageConfig();
        for (Map.Entry<String, PackageConfig.Builder> entry : packages.entrySet()) {
            configuration.addPackageConfig(entry.getValue().getName(), entry.getValue().build());
        }
    }

    // packageName => PackageConfig.Builder
    private Map<String, PackageConfig.Builder> createPackageConfig() {
        Map<String, PackageConfig.Builder> packages = new HashMap<String, PackageConfig.Builder>();

        try {
            //分析所有的 "Controller"
            for (ClassPath.ClassInfo classInfo : findControllers(controllerPackage, controllerSuffixes)) {
                List<RouteMapping> routeMappings = parseController(classInfo.load());
                for (RouteMapping routeMapping : routeMappings) {
                    //将路由转换为 action
                    ActionInfo actionInfo = routeMapping.toAction();
                    String namespace = actionInfo.getNamespace();

                    //create action config
                    PackageConfig.Builder packageCfgBuilder = findOrCreatePackage(namespace, packages);
                    ActionConfig actionCfg = createActionConfig(packageCfgBuilder, actionInfo, routeMapping);
                    packageCfgBuilder.addActionConfig(actionCfg.getName(), actionCfg);

                    //添加路由映射
                    routeMappingHandler.put(routeMapping, actionCfg);
                }
            }
        } catch (IOException e) {
            throw new IllegalStateException("could not find controllers");
        }

        return packages;
    }

    /**
     * 默认父包
     *
     * @return
     */
    private PackageConfig defaultParentPackage() {
        return configuration.getPackageConfig(defaultParentPackage);
    }

    /**
     * 查找 Package,如果不存在则创建
     *
     * @param namespace
     * @param packages
     * @return
     */
    private PackageConfig.Builder findOrCreatePackage(String namespace, Map<String, PackageConfig.Builder> packages) {
        String packageName = FREEROUTE_DEFAULT + namespace;
        PackageConfig.Builder packageCfgBuilder = packages.get(packageName);
        if (packageCfgBuilder == null) {
            PackageConfig defaultParent = this.defaultParentPackage();
            packageCfgBuilder = new PackageConfig.Builder(packageName);
            packageCfgBuilder.addParent(defaultParent);
            packageCfgBuilder.namespace(namespace);
            packages.put(packageName, packageCfgBuilder);
        }
        return packageCfgBuilder;
    }

    private ActionConfig createActionConfig(PackageConfig.Builder packageCfgBuilder, ActionInfo actionInfo, RouteMapping routeMapping) {
        String actionName = actionInfo.getActionName();

        //create action config
        String actionClass = routeMapping.getAction().getName();
        String actionMethodName = routeMapping.getMethod().getName();
        return createActionConfig(packageCfgBuilder, actionClass, actionMethodName, actionName);
    }

    private ActionConfig createActionConfig(PackageConfig.Builder packageConfigBuilder, String className, String actionName) {
        return createActionConfig(packageConfigBuilder, className, null, actionName);
    }

    protected ActionConfig createActionConfig(PackageConfig.Builder packageConfigBuilder, String className, String methodName, String actionName) {
        ActionConfig.Builder actionCfgBuilder = new ActionConfig.Builder(packageConfigBuilder.getName(), actionName, className);
        actionCfgBuilder.methodName(methodName);
        return actionCfgBuilder.build();
    }

    /**
     * 在指定的包下查找带有指定后缀的 class
     *
     * @param controllerPackage
     * @param controllerSuffixes
     * @return
     * @throws java.io.IOException
     */
    @VisibleForTesting
    static Set<ClassPath.ClassInfo> findControllers(String controllerPackage, final Set<String> controllerSuffixes) throws IOException {
        ClassPath classPath = ClassPath.from(Thread.currentThread().getContextClassLoader());

        Set<ClassPath.ClassInfo> allClasses = classPath.getTopLevelClassesRecursive(controllerPackage);
        Set<ClassPath.ClassInfo> controllers = Sets.filter(allClasses, new Predicate<ClassPath.ClassInfo>() {
            @Override
            public boolean apply(ClassPath.ClassInfo classInfo) {
                for (String controllerSuffix : controllerSuffixes) {
                    // 判断是否是指定后缀结束
                    if (classInfo.getSimpleName().endsWith(controllerSuffix)) {
                        log.trace("controller:{}", classInfo.getName());
                        return true;
                    }
                }
                return false;
            }
        });
        return controllers;
    }

    /**
     * 解析 Controller 并返回路由信息
     *
     * @param controller
     * @return
     */
    @VisibleForTesting
    static List<RouteMapping> parseController(Class controller) {
        List<RouteMapping> routes = new ArrayList<RouteMapping>();
        //遍历 Controller 的所有方法
        Method[] methods = controller.getMethods();
        if (methods == null) {
            return routes;
        }

        ContentBase contentBase = ReflectUtil.getAnnotation(controller, ContentBase.class);
        Route controllerRoute = ReflectUtil.getAnnotation(controller, Route.class);
        for (Method method : methods) {
            //查看是否有 @Route 注解, 如果有则加到路由列表中
            if (method.isAnnotationPresent(Route.class)) {
                Route methodRoute = method.getAnnotation(Route.class);
                RouteMapping routeMapping = new RouteMapping(contentBase, controllerRoute, methodRoute, controller, method);
                routes.add(routeMapping);

                if (log.isTraceEnabled()) {
                    log.trace("route: {}", routeMapping.prettyPath());
                }
            }
        }

        return routes;
    }

}
TOP

Related Classes of com.bastengao.struts2.freeroute.ControllerPackageProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.