org.makersoft.web.mvc.method.annotation.RESTfulMappingHandlerMapping.java Source code

Java tutorial

Introduction

Here is the source code for org.makersoft.web.mvc.method.annotation.RESTfulMappingHandlerMapping.java

Source

/*
 * @(#)RestfullMappingHandlerMapping.java 2013-1-31 ?23:33:33
 *
 * Copyright (c) 2011-2013 Makersoft.org all rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 *
 */
package org.makersoft.web.mvc.method.annotation;

import java.lang.reflect.Method;

import org.apache.commons.lang3.StringUtils;
import org.makersoft.log.Log;
import org.makersoft.log.LoggerFactory;
import org.makersoft.web.mvc.annotation.RESTfull;
import org.makersoft.web.mvc.builder.PackageBasedUrlPathBuilder;
import org.makersoft.web.mvc.mapping.Mapping;
import org.makersoft.web.mvc.mapping.RESTfulHelper;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
import org.springframework.web.servlet.mvc.condition.HeadersRequestCondition;
import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;

/**
 * {@link RESTfull }Controller,RESTful.
 * @see RESTfull
 * 
 * @author Feng Kuok
 */
public class RESTfulMappingHandlerMapping extends RequestMappingInfoHandlerMapping {

    private static final Log LOG = LoggerFactory.getLogger(RESTfulMappingHandlerMapping.class);

    private boolean useSuffixPatternMatch = true;

    private boolean useTrailingSlashMatch = true;

    private String[] packageLocators = new String[] { "web", "controllers", "actions", "action", "controller" };

    private String[] controllerPackages = null;

    private String controllerSuffix = "Controller";

    private String root = "application#index";

    //default constructor
    public RESTfulMappingHandlerMapping() {
        //set HandlerMapping order 
        super.setOrder(0);

        LOG.debug("Init RESTfulMappingHandlerMapping...");
    }

    /**
     * Whether to use suffix pattern match (".*") when matching patterns to
     * requests. If enabled a method mapped to "/users" also matches to "/users.*".
     * <p>The default value is {@code true}. 
     */
    public void setUseSuffixPatternMatch(boolean useSuffixPatternMatch) {
        this.useSuffixPatternMatch = useSuffixPatternMatch;
    }

    /**
     * Whether to match to URLs irrespective of the presence of a trailing slash.
     * If enabled a method mapped to "/users" also matches to "/users/".
     * <p>The default value is {@code true}.
     */
    public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
        this.useTrailingSlashMatch = useTrailingSlashMatch;
    }

    /**
     * Controller??
     * "web", "controllers", "actions", "action", "controller" 
     */
    public void setPackageLocators(String packageLocators) {
        this.packageLocators = StringUtils.split(packageLocators, ",");
    }

    /**
     * Controller??
     */
    public void setControllerPackages(String controllerPackages) {
        this.controllerPackages = StringUtils.split(controllerPackages, ",");
    }

    /**
     * Controller???,Controller
     */
    public void setControllerSuffix(String controllerSuffix) {
        this.controllerSuffix = controllerSuffix;
    }

    /**
     * ,application#index
     */
    public void setRoot(String root) {
        this.root = root;
    }

    /**
     * Whether to use suffix pattern matching.
     */
    public boolean useSuffixPatternMatch() {
        return this.useSuffixPatternMatch;
    }

    /**
     * Whether to match to URLs irrespective of the presence of a trailing  slash.
     */
    public boolean useTrailingSlashMatch() {
        return this.useTrailingSlashMatch;
    }

    @Override
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
    }

    /**
     * {@inheritDoc} 
     * Expects a handler to have a type-level @{@link Controller} annotation.
     */
    @Override
    protected boolean isHandler(Class<?> beanType) {
        return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
    }

    /**
     * Uses method and type-level @{@link RequestMapping} annotations to create
     * the RequestMappingInfo.
     * 
     * @return the created RequestMappingInfo, or {@code null} if the method
     * does not have a {@code @RequestMapping} annotation.
     * 
     * @see #getCustomMethodCondition(Method)
     * @see #getCustomTypeCondition(Class)
     */
    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = null;
        RESTfull clazzAnnotation = AnnotationUtils.findAnnotation(handlerType, RESTfull.class);
        if (clazzAnnotation != null) {
            info = createRequestMappingInfo(method, clazzAnnotation, handlerType);
            //         RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
            //         if (typeAnnotation != null) {
            //            RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
            //            info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
            //         }

        }
        return info;
    }

    /**
     * Provide a custom method-level request condition.
     * The custom {@link RequestCondition} can be of any type so long as the 
     * same condition type is returned from all calls to this method in order
     * to ensure custom request conditions can be combined and compared. 
     * @param method the handler method for which to create the condition
     * @return the condition, or {@code null}
     */
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        return null;
    }

    /**
     * Provide a custom type-level request condition.
     * The custom {@link RequestCondition} can be of any type so long as the 
     * same condition type is returned from all calls to this method in order
     * to ensure custom request conditions can be combined and compared. 
     * @param method the handler method for which to create the condition
     * @return the condition, or {@code null}
     */
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        return null;
    }

    /**
     * Created a RequestMappingInfo from a RequestMapping annotation.
     */
    private RequestMappingInfo createRequestMappingInfo(Method method, RESTfull annotation,
            Class<?> controllerClass) {

        Mapping mapping = RESTfulHelper.matchMapping(method.getName());

        if (mapping != null) {
            PackageBasedUrlPathBuilder builder = new PackageBasedUrlPathBuilder(packageLocators, controllerPackages,
                    controllerSuffix, root);

            String[] namespaceString = builder.buildUrlPath(controllerClass, mapping.getMethodName(),
                    mapping.getValues());
            if (namespaceString != null) {
                return new RequestMappingInfo(
                        new PatternsRequestCondition(namespaceString, getUrlPathHelper(), getPathMatcher(),
                                this.useSuffixPatternMatch, this.useTrailingSlashMatch),
                        new RequestMethodsRequestCondition(mapping.getRequestMethods()),
                        new ParamsRequestCondition(mapping.getParams()),
                        new HeadersRequestCondition(mapping.getHeaders()),
                        new ConsumesRequestCondition(mapping.getConsumes(), mapping.getHeaders()),
                        new ProducesRequestCondition(mapping.getProduces(), mapping.getHeaders()),
                        getCustomMethodCondition(method));
            }

        }

        return null;
    }

}