/*
* 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.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;
import org.apache.log4j.Logger;
import org.frameworkset.util.ClassUtils;
import org.frameworkset.util.annotations.HandlerMapping;
import org.frameworkset.util.annotations.MethodInfo;
import org.frameworkset.util.annotations.ModelAttribute;
import org.frameworkset.util.annotations.SessionAttributes;
import org.frameworkset.web.servlet.ModelAndView;
import org.frameworkset.web.servlet.handler.HandlerUtils;
/**
* <p>Title: HandlerMethodResolver.java</p>
* <p>Description: </p>
* <p>bboss workgroup</p>
* <p>Copyright (c) 2008</p>
* @Date 2010-10-24
* @author biaoping.yin
* @version 1.0
*/
public class HandlerMethodResolver {
private Set<MethodInfo> handlerMethods = new LinkedHashSet<MethodInfo>();
/** Methods, keyed by exception class */
private Map<Class, Method> exceptionHandlerMap = new HashMap<Class, Method>();
private final static Logger log = Logger.getLogger(HandlerMethodResolver.class);
private final Set<Method> initBinderMethods = new LinkedHashSet<Method>();
private final Set<Method> modelAttributeMethods = new LinkedHashSet<Method>();
private final HandlerMapping typeLevelMapping;
private final boolean sessionAttributesFound;
private final Set<String> sessionAttributeNames = new HashSet<String>();
private final Set<Class> sessionAttributeTypes = new HashSet<Class>();
private final Set<String> actualSessionAttributeNames = Collections.synchronizedSet(new HashSet<String>(4));
/**
* Is the supplied method a valid exception handler method?
*/
private boolean isExceptionHandlerMethod(Method method) {
Class returnType = method.getReturnType();
return ((ModelAndView.class.equals(returnType)
|| Map.class.equals(returnType)
|| String.class.equals(returnType)
|| void.class.equals(returnType)) &&
method.getParameterTypes().length >= 4 && HttpServletRequest.class
.isAssignableFrom(method.getParameterTypes()[0])
&& HttpServletResponse.class
.isAssignableFrom(method.getParameterTypes()[1])
&& PageContext.class
.isAssignableFrom(method.getParameterTypes()[2]) &&
Throwable.class.isAssignableFrom(method.getParameterTypes()[3]));
}
/**
* Registers the supplied method as an exception handler.
*/
private void registerExceptionHandlerMethod(Method method) {
this.exceptionHandlerMap.put(method.getParameterTypes()[3], method);
log.debug("Found exception handler method [" + method + "]");
}
/**
* Determine the exception handler method for the given exception.
* <p>Can return <code>null</code> if not found.
* @return a handler for the given exception type, or <code>null</code>
* @param exception the exception to handle
*/
protected Method getExceptionHandler(Throwable exception) {
Class exceptionClass = exception.getClass();
log.debug("Trying to find handler for exception class [" + exceptionClass.getName() + "]");
Method handler = this.exceptionHandlerMap.get(exceptionClass);
while (handler == null && !exceptionClass.equals(Throwable.class)) {
log.debug("Trying to find handler for exception superclass [" + exceptionClass.getName() + "]");
exceptionClass = exceptionClass.getSuperclass();
handler = this.exceptionHandlerMap.get(exceptionClass);
}
return handler;
}
/**
* Create a new HandlerMethodResolver for the specified handler type.
* @param handlerType the handler class to introspect
*/
public HandlerMethodResolver(final Class<?> handlerType) {
this.typeLevelMapping = handlerType.getAnnotation(HandlerMapping.class);
Method[] methods = handlerType.getMethods();
for(Method method:methods) {
if (isExceptionHandlerMethod(method)) {
registerExceptionHandlerMethod(method);
}
else if (HandlerUtils.isHandlerMethod(handlerType,method)) {
handlerMethods.add(new MethodInfo(ClassUtils.getMostSpecificMethod(method, handlerType),typeLevelMapping ));
}
// else if (method.isAnnotationPresent(InitBinder.class)) {
// initBinderMethods.add(ClassUtils.getMostSpecificMethod(method, handlerType));
// }
else if (method.isAnnotationPresent(ModelAttribute.class)) {
modelAttributeMethods.add(ClassUtils.getMostSpecificMethod(method, handlerType));
}
}
SessionAttributes sessionAttributes = handlerType.getAnnotation(SessionAttributes.class);
this.sessionAttributesFound = (sessionAttributes != null);
if (this.sessionAttributesFound) {
this.sessionAttributeNames.addAll(Arrays.asList(sessionAttributes.value()));
this.sessionAttributeTypes.addAll(Arrays.asList(sessionAttributes.types()));
}
}
/**
* Create a new HandlerMethodResolver for the specified handler type.
* @param handlerType the handler class to introspect
*/
public HandlerMethodResolver(final Class<?> handlerType,final String baseurls[]) {
this.typeLevelMapping = handlerType.getAnnotation(HandlerMapping.class);
Method[] methods = handlerType.getMethods();
for(Method method:methods)
{
if (HandlerUtils.isHandlerMethod(handlerType,method)) {
//System.out.println(method);
handlerMethods.add(new MethodInfo(ClassUtils.getMostSpecificMethod(method, handlerType),baseurls));
}
// else if (method.isAnnotationPresent(InitBinder.class)) {
// initBinderMethods.add(ClassUtils.getMostSpecificMethod(method, handlerType));
// }
else if (method.isAnnotationPresent(ModelAttribute.class)) {
modelAttributeMethods.add(ClassUtils.getMostSpecificMethod(method, handlerType));
}
}
SessionAttributes sessionAttributes = handlerType.getAnnotation(SessionAttributes.class);
this.sessionAttributesFound = (sessionAttributes != null);
if (this.sessionAttributesFound) {
this.sessionAttributeNames.addAll(Arrays.asList(sessionAttributes.value()));
this.sessionAttributeTypes.addAll(Arrays.asList(sessionAttributes.types()));
}
}
public final boolean hasHandlerMethods() {
return !this.handlerMethods.isEmpty();
}
public final Set<MethodInfo> getHandlerMethods() {
return this.handlerMethods;
}
public final Set<Method> getInitBinderMethods() {
return this.initBinderMethods;
}
public final Set<Method> getModelAttributeMethods() {
return this.modelAttributeMethods;
}
public boolean hasTypeLevelMapping() {
return (this.typeLevelMapping != null);
}
public HandlerMapping getTypeLevelMapping() {
return this.typeLevelMapping;
}
public boolean hasSessionAttributes() {
return this.sessionAttributesFound;
}
public boolean isSessionAttribute(String attrName, Class attrType) {
if (this.sessionAttributeNames.contains(attrName) || this.sessionAttributeTypes.contains(attrType)) {
this.actualSessionAttributeNames.add(attrName);
return true;
}
else {
return false;
}
}
public Set<String> getActualSessionAttributeNames() {
return this.actualSessionAttributeNames;
}
public void destroy()
{
if(handlerMethods != null)
{
handlerMethods.clear();
handlerMethods = null;
}
if(exceptionHandlerMap != null)
{
exceptionHandlerMap.clear();
exceptionHandlerMap = null;
}
}
}