org.debux.webmotion.server.convention.DefaultConventionScan.java Source code

Java tutorial

Introduction

Here is the source code for org.debux.webmotion.server.convention.DefaultConventionScan.java

Source

/*
 * #%L
 * Webmotion server
 * 
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2011 - 2015 Debux
 * %%
 * 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
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */
package org.debux.webmotion.server.convention;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.debux.webmotion.server.WebMotionController;
import org.debux.webmotion.server.call.HttpContext;
import org.debux.webmotion.server.mapping.Action;
import org.debux.webmotion.server.mapping.ActionRule;
import org.debux.webmotion.server.mapping.FilterRule;
import org.debux.webmotion.server.mapping.FragmentUrl;
import org.debux.webmotion.server.mapping.Mapping;
import org.debux.webmotion.server.tools.ReflectionUtils;
import org.slf4j.LoggerFactory;

/**
 * Create a mapping by convention. You have to extends WebMotionConventionController,
 * WebMotionConventionAllFilter or WebMotionConventionPackageFilter to handle the class
 * by convention.
 * 
 * @author julien
 */
public class DefaultConventionScan extends ConventionScan {

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(DefaultConventionScan.class);

    @Override
    public Mapping scan() {
        Mapping mapping = new Mapping();

        mapping.setName("default-convention");
        mapping.setExtensionPath("/");

        mapping.setActionRules(scanControllers(mapping));
        mapping.setFilterRules(scanFilters(mapping));

        return mapping;
    }

    /**
     * Scan the controllers by convention.
     */
    public List<ActionRule> scanControllers(Mapping mapping) {
        Collection<Class<?>> controllers = ReflectionUtils.getClassesBySuperClass(ConventionController.class);
        List<ActionRule> rules = new ArrayList<ActionRule>(controllers.size());

        for (Class<?> controller : controllers) {
            Method[] methods = controller.getMethods();
            for (Method method : methods) {
                Class<?> declaringClass = method.getDeclaringClass();
                if (!declaringClass.equals(Object.class) && !declaringClass.equals(WebMotionController.class)) {

                    ActionRule rule = new ActionRule();
                    rule.setMapping(mapping);
                    rule.setLine(-1);
                    rules.add(rule);

                    String className = controller.getName();
                    String methodName = method.getName();

                    // Create action
                    Action action = new Action();
                    action.setFullName(className + "." + methodName);
                    action.setType(Action.Type.ACTION);
                    rule.setAction(action);

                    // Search http method
                    String httpMethod = "*";
                    if (methodName.startsWith("create")) {
                        httpMethod = HttpContext.METHOD_PUT;
                        methodName = methodName.replaceFirst("create", "");

                    } else if (methodName.startsWith("get")) {
                        httpMethod = HttpContext.METHOD_GET;
                        methodName = methodName.replaceFirst("get", "");

                    } else if (methodName.startsWith("delete")) {
                        httpMethod = HttpContext.METHOD_DELETE;
                        methodName = methodName.replaceFirst("delete", "");

                    } else if (methodName.startsWith("update")) {
                        httpMethod = HttpContext.METHOD_POST;
                        methodName = methodName.replaceFirst("update", "");
                    }

                    rule.setMethods(Arrays.asList(httpMethod));

                    // Create path
                    List<FragmentUrl> url = new ArrayList<FragmentUrl>();

                    String simpleClassName = controller.getSimpleName();
                    Package controllerPackage = controller.getPackage();

                    if (controllerPackage != null) {
                        String packageName = controllerPackage.getName();
                        String subPackageName = StringUtils.substringAfterLast(packageName, ".");

                        if (!StringUtils.startsWithIgnoreCase(simpleClassName, subPackageName)) {
                            url.addAll(createFragmentUrlList(subPackageName));
                        }
                    }
                    url.addAll(createFragmentUrlList(simpleClassName));
                    if (methodName.length() != 0) {
                        url.addAll(createFragmentUrlList(methodName));
                    }
                    rule.setRuleUrl(url);
                }
            }
        }

        return rules;
    }

    /**
     * Scan the filters by convention.
     */
    public List<FilterRule> scanFilters(Mapping mapping) {
        Pattern allPattern = Pattern.compile("/*");

        Collection<Class<?>> filters = ReflectionUtils.getClassesBySuperClass(ConventionAllFilter.class);
        List<FilterRule> rules = new ArrayList<FilterRule>(filters.size());

        for (Class<?> filter : filters) {
            FilterRule rule = new FilterRule();
            rule.setMapping(mapping);
            rule.setLine(-1);
            rules.add(rule);

            rule.setMethods(Arrays.asList("*"));
            rule.setPattern(allPattern);

            Action action = new Action();
            action.setType(Action.Type.ACTION);
            action.setFullName(filter.getName() + ".filter");
            rule.setAction(action);
        }

        filters = ReflectionUtils.getClassesBySuperClass(ConventionPackageFilter.class);
        for (Class<?> filter : filters) {
            FilterRule rule = new FilterRule();
            rule.setMapping(mapping);
            rule.setLine(-1);
            rules.add(rule);

            Package filterPackage = filter.getPackage();
            if (filterPackage != null) {
                String packageName = filterPackage.getName();
                String subPackageName = StringUtils.substringAfterLast(packageName, ".");

                String regexp = "/" + subPackageName.toLowerCase() + "/*";
                rule.setPattern(Pattern.compile(regexp));

            } else {
                rule.setPattern(allPattern);
            }
            rule.setMethods(Arrays.asList("*"));

            Action action = new Action();
            action.setType(Action.Type.ACTION);
            action.setFullName(filter.getName() + ".filter");
            rule.setAction(action);
        }

        return rules;
    }

    /**
     * Create fragment url list from string, which split based on the camel case.
     */
    protected List<FragmentUrl> createFragmentUrlList(String name) {
        String[] values = StringUtils.splitByCharacterTypeCamelCase(name);
        List<FragmentUrl> fragmentUrls = new ArrayList<FragmentUrl>(values.length);

        for (String value : values) {
            // Add slash before each value
            FragmentUrl fragmentSlash = new FragmentUrl();
            fragmentSlash.setValue("/");

            Pattern patternSlash = Pattern.compile("^/$");
            fragmentSlash.setPattern(patternSlash);

            fragmentUrls.add(fragmentSlash);

            // Add value
            String valueLowerCase = value.toLowerCase();
            FragmentUrl fragmentUrl = new FragmentUrl();
            fragmentUrl.setValue(valueLowerCase);

            Pattern pattern = Pattern.compile("^" + valueLowerCase + "$");
            fragmentUrl.setPattern(pattern);

            fragmentUrls.add(fragmentUrl);
        }

        return fragmentUrls;
    }

}