1 16 17 package org.springframework.web.struts; 18 19 import java.lang.reflect.InvocationTargetException ; 20 import java.util.Iterator ; 21 import java.util.Locale ; 22 23 import javax.servlet.http.HttpServletRequest ; 24 25 import org.apache.commons.beanutils.BeanUtilsBean; 26 import org.apache.commons.beanutils.ConvertUtilsBean; 27 import org.apache.commons.beanutils.PropertyUtilsBean; 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 import org.apache.struts.Globals; 31 import org.apache.struts.action.ActionForm; 32 import org.apache.struts.action.ActionMessage; 33 import org.apache.struts.action.ActionMessages; 34 import org.apache.struts.util.MessageResources; 35 36 import org.springframework.context.MessageSourceResolvable; 37 import org.springframework.validation.Errors; 38 import org.springframework.validation.FieldError; 39 import org.springframework.validation.ObjectError; 40 41 89 public class SpringBindingActionForm extends ActionForm { 90 91 private static final Log logger = LogFactory.getLog(SpringBindingActionForm.class); 92 93 private static boolean defaultActionMessageAvailable = true; 94 95 96 static { 97 ConvertUtilsBean convUtils = new ConvertUtilsBean(); 102 PropertyUtilsBean propUtils = new SpringBindingAwarePropertyUtilsBean(); 103 BeanUtilsBean beanUtils = new BeanUtilsBean(convUtils, propUtils); 104 BeanUtilsBean.setInstance(beanUtils); 105 106 try { 110 ActionMessage.class.getConstructor(new Class [] {String .class, boolean.class}); 111 } 112 catch (NoSuchMethodException ex) { 113 defaultActionMessageAvailable = false; 114 } 115 } 116 117 118 private Errors errors; 119 120 private Locale locale; 121 122 private MessageResources messageResources; 123 124 125 134 public void expose(Errors errors, HttpServletRequest request) { 135 this.errors = errors; 136 137 this.locale = (Locale ) request.getSession().getAttribute(Globals.LOCALE_KEY); 139 140 this.messageResources = (MessageResources) request.getAttribute(Globals.MESSAGES_KEY); 142 143 if (errors != null && errors.hasErrors()) { 144 ActionMessages actionMessages = (ActionMessages) request.getAttribute(Globals.ERROR_KEY); 146 if (actionMessages == null) { 147 request.setAttribute(Globals.ERROR_KEY, getActionMessages()); 148 } 149 else { 150 actionMessages.add(getActionMessages()); 151 } 152 } 153 } 154 155 156 161 private ActionMessages getActionMessages() { 162 ActionMessages actionMessages = new ActionMessages(); 163 Iterator it = this.errors.getAllErrors().iterator(); 164 while (it.hasNext()) { 165 ObjectError objectError = (ObjectError) it.next(); 166 String effectiveMessageKey = findEffectiveMessageKey(objectError); 167 if (effectiveMessageKey == null && !defaultActionMessageAvailable) { 168 effectiveMessageKey = objectError.getCode(); 171 } 172 ActionMessage message = (effectiveMessageKey != null) ? 173 new ActionMessage(effectiveMessageKey, resolveArguments(objectError.getArguments())) : 174 new ActionMessage(objectError.getDefaultMessage(), false); 175 if (objectError instanceof FieldError) { 176 FieldError fieldError = (FieldError) objectError; 177 actionMessages.add(fieldError.getField(), message); 178 } 179 else { 180 actionMessages.add(ActionMessages.GLOBAL_MESSAGE, message); 181 } 182 } 183 if (logger.isDebugEnabled()) { 184 logger.debug("Final ActionMessages used for binding: " + actionMessages); 185 } 186 return actionMessages; 187 } 188 189 private Object [] resolveArguments(Object [] arguments) { 190 if (arguments == null || arguments.length == 0) { 191 return arguments; 192 } 193 for (int i = 0; i < arguments.length; i++) { 194 Object arg = arguments[i]; 195 if (arg instanceof MessageSourceResolvable) { 196 MessageSourceResolvable resolvable = (MessageSourceResolvable)arg; 197 String [] codes = resolvable.getCodes(); 198 boolean resolved = false; 199 if (this.messageResources != null) { 200 for (int j = 0; j < codes.length; j++) { 201 String code = codes[j]; 202 if (this.messageResources.isPresent(this.locale, code)) { 203 arguments[i] = this.messageResources.getMessage( 204 this.locale, code, resolveArguments(resolvable.getArguments())); 205 resolved = true; 206 break; 207 } 208 } 209 } 210 if (!resolved) { 211 arguments[i] = resolvable.getDefaultMessage(); 212 } 213 } 214 } 215 return arguments; 216 } 217 218 223 private String findEffectiveMessageKey(ObjectError error) { 224 if (this.messageResources != null) { 225 String [] possibleMatches = error.getCodes(); 226 for (int i = 0; i < possibleMatches.length; i++) { 227 if (logger.isDebugEnabled()) { 228 logger.debug("Looking for error code '" + possibleMatches[i] + "'"); 229 } 230 if (this.messageResources.isPresent(this.locale, possibleMatches[i])) { 231 if (logger.isDebugEnabled()) { 232 logger.debug("Found error code '" + possibleMatches[i] + "' in resource bundle"); 233 } 234 return possibleMatches[i]; 235 } 236 } 237 } 238 if (logger.isDebugEnabled()) { 239 logger.debug("Could not find a suitable message error code, returning default message"); 240 } 241 return null; 242 } 243 244 245 255 private Object getFieldValue(String propertyPath) throws NoSuchMethodException { 256 if (this.errors == null) { 257 throw new NoSuchMethodException ( 258 "No bean properties exposed to Struts binding - performing Spring binding later on"); 259 } 260 return this.errors.getFieldValue(propertyPath); 261 } 262 263 264 269 private static class SpringBindingAwarePropertyUtilsBean extends PropertyUtilsBean { 270 271 public Object getNestedProperty(Object bean, String propertyPath) 272 throws IllegalAccessException , InvocationTargetException , NoSuchMethodException { 273 274 if (bean instanceof SpringBindingActionForm) { 276 SpringBindingActionForm form = (SpringBindingActionForm) bean; 277 return form.getFieldValue(propertyPath); 278 } 279 280 return super.getNestedProperty(bean, propertyPath); 282 } 283 } 284 285 } 286 | Popular Tags |