1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
151
152 return null;
153 }
154
155 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
156 this.applicationContext = applicationContext;
157 }
158 }