/* * Copyright 2008 biaoping.yin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.frameworkset.web.servlet.handler.annotations; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.frameworkset.util.ClassUtil; import org.frameworkset.util.annotations.AnnotationUtils; import org.frameworkset.util.annotations.HandlerMapping; import org.frameworkset.util.annotations.HttpMethod; import org.frameworkset.web.HttpRequestMethodNotSupportedException; import org.frameworkset.web.servlet.handler.AbstractDetectingUrlHandlerMapping; import org.frameworkset.web.servlet.handler.HandlerUtils; import com.frameworkset.util.StringUtil; /** * <p>Title: DefaultAnnotationHandlerMapping.java</p> * <p>Description: </p> * <p>bboss workgroup</p> * <p>Copyright (c) 2008</p> * @Date 2010-10-23 * @author biaoping.yin * @version 1.0 */ public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandlerMapping { private boolean useDefaultSuffixPattern = true; private Map<Class, HandlerMapping> cachedMappings = new HashMap<Class, HandlerMapping>(); /** * Set whether to register paths using the default suffix pattern as well: * i.e. whether "/users" should be registered as "/users.*" too. * <p>Default is "true". Turn this convention off if you intend to interpret * your <code>@HandlerMapping</code> paths strictly. * <p>Note that paths which include a ".xxx" suffix already will not be * transformed using the default suffix pattern in any case. */ public void setUseDefaultSuffixPattern(boolean useDefaultSuffixPattern) { this.useDefaultSuffixPattern = useDefaultSuffixPattern; } // /** // * Checks for presence of the {@link org.frameworkset.util.annotations.HandlerMapping} // * annotation on the handler class and on any of its methods. // */ // protected String[] determineUrlsForHandler(String beanName) { // ApplicationContext context = getApplicationContext(); // Pro beaninfos = context.getProBean(beanName); // if(!beaninfos.isBean()) // return null; // Class<?> handlerType = beaninfos.getBeanClass(); //// ListableBeanFactory bf = (context instanceof ConfigurableApplicationContext ? //// ((ConfigurableApplicationContext) context).getBeanFactory() : context); //// GenericBeanFactoryAccessor bfa = new GenericBeanFactoryAccessor(bf); // // //获取类级url和controller映射关系 // HandlerMapping mapping = AnnotationUtils.findAnnotation(handlerType, HandlerMapping.class); // // if (mapping != null) { // // @HandlerMapping found at type level // this.cachedMappings.put(handlerType, mapping); // Set<String> urls = new LinkedHashSet<String>(); // String[] paths = mapping.value(); // if (paths.length > 0) { // // @HandlerMapping specifies paths at type level // for (String path : paths) { // addUrlsForPath(urls, path); // } // // return StringUtil.toStringArray(urls); // } // else { // // actual paths specified by @HandlerMapping at method level // return determineUrlsForHandlerMethods(handlerType); // } // } // else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) { // // @HandlerMapping to be introspected at method level // return determineUrlsForHandlerMethods(handlerType); // } // else { // return null; // } // } protected String[] determineUrlsForHandler(String beanName) { return HandlerUtils.determineUrlsForHandler(getApplicationContext(), beanName, cachedMappings); } // /** // * Checks for presence of the {@link org.frameworkset.util.annotations.HandlerMapping} // * annotation on the handler class and on any of its methods. // */ // protected String[] determineUrlsForHandler(String beanName) { // ApplicationContext context = getApplicationContext(); // Pro beaninfos = context.getProBean(beanName); // if(!beaninfos.isBean()) // return null; // final Class<?> handlerType = beaninfos.getBeanClass(); //// ListableBeanFactory bf = (context instanceof ConfigurableApplicationContext ? //// ((ConfigurableApplicationContext) context).getBeanFactory() : context); //// GenericBeanFactoryAccessor bfa = new GenericBeanFactoryAccessor(bf); // // //获取类级url和controller映射关系 // HandlerMapping mapping = AnnotationUtils.findAnnotation(handlerType, HandlerMapping.class); // // if (mapping != null) { // // @HandlerMapping found at type level // this.cachedMappings.put(handlerType, mapping); // // Set<String> urls = new LinkedHashSet<String>(); // final Set<Method> handlerMethods = new LinkedHashSet<Method>(); // ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() { // public void doWith(Method method) { // if (method.isAnnotationPresent(HandlerMapping.class)) { // handlerMethods.add(ClassUtils.getMostSpecificMethod(method, handlerType)); // } // } // }); // String[] paths = mapping.value(); // if (paths.length > 0) { // // @HandlerMapping specifies paths at type level // for (String path : paths) { // // // if(mapping.restful()) // { // this.addUrlsForRestfulPath(urls, path, handlerMethods); // } // else // { // addUrlsForPath(urls, path); // } // } // // return StringUtil.toStringArray(urls); // } // else { // // actual paths specified by @HandlerMapping at method level // return determineUrlsForHandlerMethods(handlerType); // } // } // else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) { // // @HandlerMapping to be introspected at method level // return determineUrlsForHandlerMethods(handlerType); // } // else { // return null; // } // } // /** // * Derive URL mappings from the handler's method-level mappings. // * @param handlerType the handler type to introspect // * @return the array of mapped URLs // */ // protected String[] determineUrlsForHandlerMethods(Class<?> handlerType) { // final Set<String> urls = new LinkedHashSet<String>(); // ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() { // public void doWith(Method method) { // HandlerMapping mapping = method.getAnnotation(HandlerMapping.class); // if (mapping != null) { // String[] mappedPaths = mapping.value(); // for (int i = 0; i < mappedPaths.length; i++) { // addUrlsForPath(urls, mappedPaths[i]); // } // } // } // }); // return StringUtil.toStringArray(urls); // } // // /** // * Add URLs and/or URL patterns for the given path. // * @param urls the Set of URLs for the current bean // * @param path the currently introspected path // */ // protected void addUrlsForPath(Set<String> urls, String path) { //// Iterator<Method> methods = handlermethods.iterator(); //// while(methods.hasNext()) //// { //// urls.addAll(this.getUrl(path, restful, methods.next())); // urls.add(path); // if (this.useDefaultSuffixPattern && path.indexOf('.') == -1) { // urls.add(path + ".*"); // } //// } // } // // /** // * Add URLs and/or URL patterns for the given path. // * @param urls the Set of URLs for the current bean // * @param path the currently introspected path // */ // protected void addUrlsForRestfulPath(Set<String> urls, String path,Set<Method> handlermethods) { // Iterator<Method> methods = handlermethods.iterator(); // while(methods.hasNext()) // { // urls.addAll(this.getRestfulUrl(path, methods.next())); // // } // } // //// protected int convert(HttpMethod requestMethod) //// { //// //// } // protected Set<String> getRestfulUrl(String path, Method method) // { // // String url = path; // Set<String> urls = new LinkedHashSet<String>(); // HandlerMapping mapping = method.getAnnotation(HandlerMapping.class); //// MethodInfo methodInfo = new MethodInfo(method); // String[] mappedPaths = mapping.value(); // if (mappedPaths != null && mappedPaths.length > 0) { // String mappedPath = mappedPaths[0]; // StringBuffer pathUrl = new StringBuffer(); // pathUrl.append(url); // for(int i = 0; i < mappedPath.length(); i ++ ) // { // if(mappedPath.charAt(i) == '/') // pathUrl.append("/*"); // // } // urls.add(pathUrl.toString()); // pathUrl = null; // } // else // { // urls.add(url); // } // return urls; // // } /** * Validate the given annotated handler against the current request. * @see #validateMapping */ protected void validateHandler(Object handler, HttpServletRequest request) throws Exception { HandlerMapping mapping = this.cachedMappings.get(ClassUtil.getClassInfo(handler.getClass()).getClazz()); if (mapping == null) { mapping = AnnotationUtils.findAnnotation(ClassUtil.getClassInfo(handler.getClass()).getClazz(), HandlerMapping.class); } if (mapping != null) { validateMapping(mapping, request); } } /** * Validate the given type-level mapping metadata against the current request, * checking HTTP request method and parameter conditions. * @param mapping the mapping metadata to validate * @param request current HTTP request * @throws Exception if validation failed */ protected void validateMapping(HandlerMapping mapping, HttpServletRequest request) throws Exception { HttpMethod[] mappedMethods = mapping.method(); if (!ServletAnnotationMappingUtils.checkRequestMethod(mappedMethods, request)) { String[] supportedMethods = new String[mappedMethods.length]; for (int i = 0; i < mappedMethods.length; i++) { supportedMethods[i] = mappedMethods[i].name(); } throw new HttpRequestMethodNotSupportedException(request.getMethod(), supportedMethods); } String[] mappedParams = mapping.params(); if (!ServletAnnotationMappingUtils.checkParameters(mappedParams, request)) { throw new ServletException("Parameter conditions {" + StringUtil.arrayToDelimitedString(mappedParams, ", ") + "} not met for request parameters: " + request.getParameterMap()); } } @Override public void destroy() { // TODO Auto-generated method stub super.destroy(); if(cachedMappings != null) { cachedMappings.clear(); cachedMappings = null; } } }