View Javadoc

1   /*
2    Spring-Annotation, an easy way to configre Spring-Framework without all that XML.
3    Copyright (C) 2007 Spring-Annotation Development Team (http://www.urubatan.com.br)
4   
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9   
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14  
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  
19   <a href="http://www.gnu.org/licenses/lgpl.html">http://www.gnu.org/licenses/lgpl.html</a>
20   */
21  package net.sourceforge.sannotations.aop;
22  
23  import java.lang.reflect.Method;
24  import java.util.Iterator;
25  import java.util.Locale;
26  
27  import javax.faces.application.FacesMessage;
28  import javax.faces.component.UIComponent;
29  import javax.faces.component.UIInput;
30  import javax.faces.context.FacesContext;
31  import javax.faces.el.ValueBinding;
32  
33  import net.sourceforge.sannotations.annotation.Bean;
34  import net.sourceforge.sannotations.annotation.IfInvalid;
35  
36  import org.aspectj.lang.ProceedingJoinPoint;
37  import org.aspectj.lang.Signature;
38  import org.aspectj.lang.annotation.Around;
39  import org.aspectj.lang.annotation.Aspect;
40  import org.aspectj.lang.annotation.Pointcut;
41  import org.aspectj.lang.reflect.MethodSignature;
42  import org.hibernate.validator.ClassValidator;
43  import org.hibernate.validator.InvalidValue;
44  import org.springframework.beans.BeansException;
45  import org.springframework.context.ApplicationContext;
46  import org.springframework.context.ApplicationContextAware;
47  import org.springframework.context.MessageSource;
48  import org.springframework.context.support.MessageSourceResourceBundle;
49  
50  /***
51   * Aspect that intercepts the execution of methods annotated with
52   * 
53   * @IfInvalid and validates the owner managed bean.
54   * @author Urubatan
55   */
56  @Aspect
57  public class ValidationInterceptor implements ApplicationContextAware {
58  	private ApplicationContext	applicationContext;
59  
60  	@Pointcut("@within(net.sourceforge.sannotations.annotation.ManagedBean)")
61  	public void inAManagedBean() {
62  	}
63  
64  	@Pointcut("execution(@net.sourceforge.sannotations.annotation.IfInvalid public String *.*())")
65  	public void needValidation() {
66  	}
67  
68  	@SuppressWarnings("unchecked")
69  	@Around("inAManagedBean() && needValidation()")
70  	public Object actionNeedingValidation(final ProceedingJoinPoint thisJoinPoint) throws Throwable {
71  		ClassValidator cv;
72  		if ((this.applicationContext != null) && this.applicationContext.containsBean("messageSource")) {
73  			final MessageSource ms = (MessageSource) this.applicationContext.getBean("messageSource");
74  			Locale loc = FacesContext.getCurrentInstance().getViewRoot().getLocale();
75  			if (loc == null) {
76  				loc = FacesContext.getCurrentInstance().getApplication().getDefaultLocale();
77  			}
78  			final MessageSourceResourceBundle rb = new MessageSourceResourceBundle(ms, loc);
79  			cv = new ClassValidator(thisJoinPoint.getTarget().getClass(), rb);
80  		} else {
81  			cv = new ClassValidator(thisJoinPoint.getTarget().getClass());
82  		}
83  		final InvalidValue[] invalidmessages = cv.getInvalidValues(thisJoinPoint.getTarget());
84  		int unresolvedCount = 0;
85  		if ((invalidmessages != null) && (invalidmessages.length > 0)) {
86  			final Signature sig = thisJoinPoint.getSignature();
87  			IfInvalid ann = null;
88  			final String beanName = this.findName(thisJoinPoint.getTarget());
89  			final FacesContext fc = FacesContext.getCurrentInstance();
90  			if (sig instanceof MethodSignature) {
91  				final Method method = ((MethodSignature) sig).getMethod();
92  				ann = method.getAnnotation(IfInvalid.class);
93  			}
94  			for (final InvalidValue iv : invalidmessages) {
95  				final String message = iv.getMessage();
96  				final String clientId = this.findClientId(fc, fc.getViewRoot(), beanName, iv.getPropertyPath());
97  				if (clientId != null) {
98  					fc.addMessage(clientId, new FacesMessage(message));
99  				} else {
100 					unresolvedCount++;
101 				}
102 			}
103 			if ((unresolvedCount == 0) || (unresolvedCount < invalidmessages.length)) {
104 				return (ann == null) || "".equals(ann.outcome()) ? null : ann.outcome();
105 			} else {
106 				return thisJoinPoint.proceed();
107 			}
108 		} else {
109 			return thisJoinPoint.proceed();
110 		}
111 	}
112 
113 	/***
114 	 * method that traverses an UIComponent and searches for children of it of type UIInput that have the value binding pointing to the property that has some error.
115 	 * 
116 	 * @param ctx
117 	 * @param viewRoot
118 	 * @param beanName
119 	 * @param propertyPath
120 	 * @return
121 	 */
122 	private String findClientId(final FacesContext ctx, final UIComponent viewRoot, final String beanName, final String propertyPath) {
123 		final Iterator<?> i = viewRoot.getFacetsAndChildren();
124 		while (i.hasNext()) {
125 			final UIComponent c = (UIComponent) i.next();
126 			if (c instanceof UIInput) {
127 				final UIInput inp = (UIInput) c;
128 				final ValueBinding vb = inp.getValueBinding("value");
129 				if (vb != null) {
130 					if (("#{" + beanName + "." + propertyPath + "}").equals(vb.getExpressionString())) {
131 						return inp.getClientId(ctx);
132 					}
133 				}
134 			} else {
135 				final String val = this.findClientId(ctx, c, beanName, propertyPath);
136 				if (val != null) {
137 					return val;
138 				}
139 			}
140 		}
141 		return null;
142 	}
143 
144 	private String findName(final Object target) {
145 		final Bean b = target.getClass().getAnnotation(Bean.class);
146 		if (b != null) {
147 			return b.name();
148 		}
149 		/*
150 		 * final Name n = target.getClass().getAnnotation(Name.class); if (n != null) { return n.value(); }
151 		 */
152 		return null;
153 	}
154 
155 	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
156 		this.applicationContext = applicationContext;
157 	}
158 }