/* * Copyright 2002-20085 the original author or authors. * * 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.springmodules.validation.valang.javascript.taglib; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; import org.springframework.validation.Validator; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.servlet.mvc.BaseCommandController; import org.springmodules.validation.valang.ValangValidator; /** * Spring MVC interceptor implementation that will automatically export Valang validation rules that are used by any of * the intercepted handlers into the the ModelAndView so that they are accessible to the custom tag * <code>ValangValidateTag</code>. * <p/> * <p> * Does nothing if the intercepted handler is neither an instance of <code>BaseCommandController</code>, nor a proxied * <code>BaseCommandController</code>. * </p> * <p> * This will also do nothing if the handler did not export a command object into the model. Obviously the rules will * only be picked up from all validators of type {@link ValangValidator}. * * @author Oliver Hutchison * @author Uri Boness * @author Colin Yates * * @see ValangValidateTag * @see ValangValidator */ public class ValangRulesExportInterceptor extends HandlerInterceptorAdapter { private static final Log logger = LogFactory.getLog(ValangRulesExportInterceptor.class); public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { BaseCommandController controller = retrieveBaseCommandControllerIfPossible(handler); if (controller == null) { if (logger.isDebugEnabled()) { logger.debug("Controller is of type " + controller.getClass() + " so ignoring"); } return; } Map model = modelAndView.getModel(); String commandName = controller.getCommandName(); if (model == null || !model.containsKey(commandName)) { if (logger.isWarnEnabled()) { logger.debug("Handler '" + handler + "' did not export command object '" + controller.getCommandName() + "'; no rules added to model"); } return; } Validator[] validators = controller.getValidators(); for (int i = 0; i < validators.length; i++) { if (!ValangValidator.class.isInstance(validators[i])) { continue; } if (logger.isDebugEnabled()) { logger.debug("Adding Valang rules from handler '" + handler + "' to model"); } ValangValidator validator = (ValangValidator) validators[i]; ValangJavaScriptTagUtils.addValangRulesToModel(commandName, validator.getRules(), model); } } /** * Convert the specified <code>handler</code> to a {@link BaseCommandController} if possible. * * <p> * If the <code>handler</code> is type compatible with a <code>BaseCommandController</code> then it will simply be * cast. * </p> * <p> * If the <code>handler</code> is a Spring JDK (or CGLIB) proxy, then it will unravelled and returned (assuming the * target is a <code>BaseCommandController</code>. * </p> * If neither of the above strategies work, <code>null</code> will be returned. * * @param handler * the handler to convert to a <code>BaseCommandController</code>. * @return a <code>BaseCommandController</code> or <code>null</code> if <code>handler</code> cannot be converted. * @throws Exception */ private BaseCommandController retrieveBaseCommandControllerIfPossible(Object handler) throws Exception { BaseCommandController baseCommandController = null; if (BaseCommandController.class.isAssignableFrom(handler.getClass())) { if (logger.isDebugEnabled()) { logger.debug("handler is type compatible, simply cast"); } baseCommandController = (BaseCommandController) handler; } else if (AopUtils.isAopProxy(handler)) { if (logger.isDebugEnabled()) { logger.debug("handler is AOP proxy"); } Advised advisedObject = (Advised) handler; Class proxiedClass = advisedObject.getTargetClass(); Object target = advisedObject.getTargetSource().getTarget(); // convert (if possible) the target. baseCommandController = retrieveBaseCommandControllerIfPossible(target); } if (logger.isDebugEnabled()) { logger.debug("Cannot convert handler to BaseCommandController"); } return baseCommandController; } }