1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
package org.apache.shale.validator.faces; |
19 | |
|
20 | |
import java.io.IOException; |
21 | |
import java.util.ArrayList; |
22 | |
import java.util.Iterator; |
23 | |
import java.util.LinkedHashMap; |
24 | |
import java.util.List; |
25 | |
import java.util.Map; |
26 | |
import java.util.Set; |
27 | |
import javax.faces.component.EditableValueHolder; |
28 | |
import javax.faces.component.UIComponent; |
29 | |
import javax.faces.component.UIComponentBase; |
30 | |
import javax.faces.component.UIForm; |
31 | |
import javax.faces.component.UINamingContainer; |
32 | |
import javax.faces.context.FacesContext; |
33 | |
import javax.faces.context.ResponseWriter; |
34 | |
import javax.faces.el.ValueBinding; |
35 | |
import org.apache.commons.validator.ValidatorAction; |
36 | |
import org.apache.commons.validator.Var; |
37 | |
import org.apache.shale.util.Tags; |
38 | |
import org.apache.shale.validator.CommonsValidator; |
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | 13 | public class ValidatorScript extends UIComponentBase { |
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
private String functionName; |
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | 13 | private Map validators = new LinkedHashMap(); |
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | 13 | private Map validatorVars = new LinkedHashMap(); |
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
public String getRendererType() { |
82 | 26 | return null; |
83 | |
} |
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
public String getFamily() { |
94 | |
return null; |
95 | |
} |
96 | |
|
97 | |
|
98 | |
|
99 | |
|
100 | |
|
101 | |
|
102 | |
|
103 | |
public String getFunctionName() { |
104 | |
|
105 | 13 | if (this.functionName != null) { |
106 | 13 | return functionName; |
107 | |
} |
108 | |
ValueBinding _vb = getValueBinding("functionName"); |
109 | |
if (_vb != null) { |
110 | |
return (String) _vb.getValue(getFacesContext()); |
111 | |
} else { |
112 | |
return null; |
113 | |
} |
114 | |
|
115 | |
} |
116 | |
|
117 | |
|
118 | |
|
119 | |
|
120 | |
|
121 | |
|
122 | |
|
123 | |
public void setFunctionName(String functionName) { |
124 | 13 | this.functionName = functionName; |
125 | 13 | } |
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | |
|
131 | |
|
132 | |
|
133 | |
|
134 | |
public void restoreState(FacesContext context, Object state) { |
135 | |
|
136 | |
Object values[] = (Object[]) state; |
137 | |
super.restoreState(context, values[0]); |
138 | |
this.functionName = (String) values[1]; |
139 | |
|
140 | |
} |
141 | |
|
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
|
147 | |
|
148 | |
|
149 | |
public Object saveState(FacesContext context) { |
150 | |
|
151 | |
Object values[] = new Object[2]; |
152 | |
values[0] = super.saveState(context); |
153 | |
values[1] = this.functionName; |
154 | |
return values; |
155 | |
|
156 | |
} |
157 | |
|
158 | |
|
159 | |
|
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
|
165 | |
private Map getValidatorsGroupByFormName() { |
166 | |
|
167 | 13 | Map formValidators = new LinkedHashMap(); |
168 | |
|
169 | 13 | Iterator vi = validators.entrySet().iterator(); |
170 | 28 | while (vi.hasNext()) { |
171 | |
|
172 | 15 | Map.Entry typeEntry = (Map.Entry) vi.next(); |
173 | 15 | Map typeMap = (Map) typeEntry.getValue(); |
174 | |
|
175 | 15 | String type = (String) typeEntry.getKey(); |
176 | |
|
177 | 15 | Iterator ti = typeMap.entrySet().iterator(); |
178 | 45 | while (ti.hasNext()) { |
179 | |
|
180 | 30 | Map.Entry idEntry = (Map.Entry) ti.next(); |
181 | 30 | String id = (String) idEntry.getKey(); |
182 | 30 | CommonsValidator v = (CommonsValidator) idEntry.getValue(); |
183 | 30 | String formName = v.getFormName(); |
184 | |
|
185 | 30 | Map formTypeMap = (Map) formValidators.get(formName); |
186 | 30 | if (formTypeMap == null) { |
187 | 26 | formTypeMap = new LinkedHashMap(); |
188 | 26 | formValidators.put(formName, formTypeMap); |
189 | |
} |
190 | |
|
191 | 30 | Map formTypeIdMap = (Map) formTypeMap.get(type); |
192 | 30 | if (formTypeIdMap == null) { |
193 | 30 | formTypeIdMap = new LinkedHashMap(); |
194 | 30 | formTypeMap.put(type, formTypeIdMap); |
195 | |
} |
196 | |
|
197 | 30 | formTypeIdMap.put(id, v); |
198 | 30 | } |
199 | |
|
200 | 15 | } |
201 | |
|
202 | 13 | return formValidators; |
203 | |
|
204 | |
} |
205 | |
|
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
private void addValidator(String type, String id, CommonsValidator v) { |
215 | |
|
216 | 30 | Map map = (Map) validators.get(type); |
217 | 30 | if (map == null) { |
218 | 15 | map = new LinkedHashMap(); |
219 | 15 | validators.put(type, map); |
220 | |
} |
221 | 30 | if (id != null) { |
222 | 30 | map.put(id, v); |
223 | |
} |
224 | 30 | } |
225 | |
|
226 | |
|
227 | |
|
228 | |
|
229 | |
|
230 | |
|
231 | |
|
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
|
237 | |
|
238 | |
private void findCommonsValidators(UIComponent c, FacesContext context) { |
239 | 79 | if (c instanceof EditableValueHolder && c.isRendered()) { |
240 | 26 | EditableValueHolder h = (EditableValueHolder) c; |
241 | 26 | javax.faces.validator.Validator[] vs = h.getValidators(); |
242 | 52 | for (int i = 0; i < vs.length; i++) { |
243 | 26 | if (vs[i] instanceof CommonsValidator) { |
244 | 26 | CommonsValidator v = (CommonsValidator) vs[i]; |
245 | 26 | v.setFormName(findForm(context, c)); |
246 | 26 | if (Boolean.TRUE.equals(v.getClient())) { |
247 | |
|
248 | |
|
249 | 26 | Map clientIds = (Map) c.getAttributes().get(ValidatorInputRenderer.VALIDATOR_CLIENTIDS_ATTR); |
250 | 26 | if (clientIds != null) { |
251 | |
|
252 | |
validatorVars.putAll(clientIds); |
253 | |
Iterator ci = clientIds.entrySet().iterator(); |
254 | |
while (ci.hasNext()) { |
255 | |
Map.Entry e = (Map.Entry) ci.next(); |
256 | |
|
257 | |
String id = (String) e.getKey(); |
258 | |
addValidator(v.getType(), id, v); |
259 | |
|
260 | |
ValidatorAction action = v.getValidatorAction(); |
261 | |
List list = action.getDependencyList(); |
262 | |
Iterator iter = list.iterator(); |
263 | |
while (iter.hasNext()) { |
264 | |
String type = (String) iter.next(); |
265 | |
addValidator(type, id, v); |
266 | |
} |
267 | |
|
268 | |
} |
269 | |
|
270 | |
} else { |
271 | |
|
272 | 26 | String id = c.getClientId(context); |
273 | 26 | addValidator(v.getType(), id, v); |
274 | |
|
275 | 26 | ValidatorAction action = v.getValidatorAction(); |
276 | 26 | List list = action.getDependencyList(); |
277 | 26 | Iterator iter = list.iterator(); |
278 | 30 | while (iter.hasNext()) { |
279 | 4 | String type = (String) iter.next(); |
280 | 4 | addValidator(type, id, v); |
281 | 4 | } |
282 | |
} |
283 | |
|
284 | |
} |
285 | 26 | if (Boolean.TRUE.equals(v.getServer())) { |
286 | |
|
287 | |
|
288 | |
|
289 | |
|
290 | 26 | if ("required".equals(v.getType())) { |
291 | 2 | h.setRequired(true); |
292 | |
} |
293 | |
} |
294 | |
} |
295 | |
} |
296 | |
} |
297 | |
|
298 | 79 | Iterator childrenIterator = c.getFacetsAndChildren(); |
299 | 145 | while (childrenIterator.hasNext()) { |
300 | 66 | UIComponent child = (UIComponent) childrenIterator.next(); |
301 | 66 | findCommonsValidators(child, context); |
302 | 66 | } |
303 | 79 | childrenIterator = null; |
304 | 79 | } |
305 | |
|
306 | |
|
307 | |
|
308 | |
|
309 | |
|
310 | |
|
311 | |
|
312 | |
|
313 | |
|
314 | |
private void writeScriptStart(ResponseWriter writer) throws IOException { |
315 | 13 | writer.startElement("script", this); |
316 | 13 | writer.writeAttribute("type", "text/javascript", null); |
317 | 13 | writer.writeAttribute("language", "Javascript1.1", null); |
318 | 13 | writer.write("\n"); |
319 | 13 | } |
320 | |
|
321 | |
|
322 | |
|
323 | |
|
324 | |
|
325 | |
|
326 | |
|
327 | |
|
328 | |
|
329 | |
private void writeScriptEnd(ResponseWriter writer) throws IOException { |
330 | 13 | writer.write("\n"); |
331 | 13 | writer.endElement("script"); |
332 | 13 | } |
333 | |
|
334 | |
|
335 | |
|
336 | |
|
337 | |
|
338 | |
|
339 | |
|
340 | |
|
341 | |
|
342 | |
|
343 | |
|
344 | |
private void writeValidationFunctions(ResponseWriter writer, |
345 | |
FacesContext context) throws IOException { |
346 | |
|
347 | 13 | StringBuffer buff = new StringBuffer(); |
348 | 13 | buff.append("var bCancel = false;\n") |
349 | |
.append("function ") |
350 | |
.append(getAttributes().get("functionName").toString()).append("(form) {\n") |
351 | |
.append("\tvar bValid = true;\n") |
352 | |
.append("\tvar sFormName = jcv_retrieveFormName(form);\n"); |
353 | |
|
354 | 13 | Map formValidators = getValidatorsGroupByFormName(); |
355 | 13 | Iterator formIter = formValidators.entrySet().iterator(); |
356 | 39 | while (formIter.hasNext()) { |
357 | 26 | Map.Entry typeEntry = (Map.Entry) formIter.next(); |
358 | 26 | String formName = (String) typeEntry.getKey(); |
359 | 26 | Map formTypeValidators = (Map) typeEntry.getValue(); |
360 | |
|
361 | |
|
362 | |
|
363 | 26 | buff.append("\tif ((bValid && !bCancel && (\"") |
364 | |
.append(formName) |
365 | |
.append("\" == sFormName))) {\n") |
366 | |
.append("\t\tbValid = ("); |
367 | |
|
368 | |
|
369 | 26 | Iterator iter = getTypesOrderedByDependencies(formTypeValidators.keySet()).iterator(); |
370 | 26 | boolean first = true; |
371 | 56 | while (iter.hasNext()) { |
372 | 30 | String type = (String) iter.next(); |
373 | 30 | ValidatorAction a = CommonsValidator.getValidatorAction(type); |
374 | |
|
375 | 30 | buff.append((!first ? " && " : "")) |
376 | |
.append(a.getJsFunctionName()) |
377 | |
.append("(form)"); |
378 | 30 | first = false; |
379 | |
|
380 | 30 | writer.write("function "); |
381 | 30 | StringBuffer callback = new StringBuffer(); |
382 | |
|
383 | |
|
384 | |
|
385 | 30 | String fnameMnemonic = CommonsValidator.getJsCallbackMnemonic(type); |
386 | |
|
387 | 30 | callback.append(formName).append('_').append(fnameMnemonic); |
388 | 30 | writer.write(callback.toString()); |
389 | 30 | writer.write("() { \n"); |
390 | |
|
391 | 30 | Map map = (Map) formTypeValidators.get(type); |
392 | 30 | Iterator iter2 = map.keySet().iterator(); |
393 | 30 | int k = 0; |
394 | 60 | while (iter2.hasNext()) { |
395 | 30 | String id = (String) iter2.next(); |
396 | 30 | CommonsValidator v = (CommonsValidator) map.get(id); |
397 | 30 | writer.write("this[" + k + "] = "); |
398 | 30 | k++; |
399 | 30 | writeJavaScriptParams(writer, context, id, v); |
400 | 30 | writer.write(";\n"); |
401 | 30 | } |
402 | 30 | writer.write("\t}\n"); |
403 | 30 | } |
404 | |
|
405 | 26 | buff.append(");\n\t\n}"); |
406 | |
|
407 | 26 | } |
408 | 13 | formValidators.clear(); |
409 | |
|
410 | |
|
411 | 13 | buff.append("\n\treturn bValid;\n") |
412 | |
.append("}\n"); |
413 | |
|
414 | 13 | writer.write(buff.toString()); |
415 | |
|
416 | |
|
417 | |
|
418 | 13 | List types = new ArrayList(validators.keySet()); |
419 | 13 | types.add("includeJavaScriptUtilities"); |
420 | |
|
421 | 13 | Iterator iter = types.iterator(); |
422 | 41 | while (iter.hasNext()) { |
423 | 28 | String type = (String) iter.next(); |
424 | 28 | ValidatorAction a = CommonsValidator.getValidatorAction(type); |
425 | 28 | writer.write(a.getJavascript()); |
426 | 28 | writer.write("\n"); |
427 | 28 | } |
428 | |
|
429 | 13 | types.clear(); |
430 | |
|
431 | 13 | } |
432 | |
|
433 | |
|
434 | |
|
435 | |
|
436 | |
|
437 | |
|
438 | |
|
439 | |
|
440 | |
|
441 | |
|
442 | |
|
443 | |
|
444 | |
|
445 | |
|
446 | |
private String escapeJavascript(String str) { |
447 | 54 | if (str == null) { |
448 | |
return null; |
449 | |
} |
450 | |
|
451 | 54 | int length = str.length(); |
452 | |
|
453 | 54 | if (length == 0) { |
454 | |
return str; |
455 | |
} |
456 | |
|
457 | |
|
458 | 54 | StringBuffer out = new StringBuffer(length + 4); |
459 | |
|
460 | |
|
461 | 362 | for (int i = 0; i < length; i++) { |
462 | 308 | char c = str.charAt(i); |
463 | |
|
464 | 308 | if ((c == '"') || (c == '\'') || (c == '\\') || (c == '\n') |
465 | |
|| (c == '\r')) { |
466 | |
out.append('\\'); |
467 | |
} |
468 | |
|
469 | 308 | out.append(c); |
470 | |
} |
471 | |
|
472 | 54 | return out.toString(); |
473 | |
} |
474 | |
|
475 | |
|
476 | |
|
477 | |
|
478 | |
|
479 | |
|
480 | |
|
481 | |
|
482 | |
|
483 | |
private List getTypesOrderedByDependencies(Set typeSet) { |
484 | |
|
485 | 26 | List tmpList = new ArrayList(typeSet); |
486 | |
|
487 | 30 | ordered: for (int i = 0; i < tmpList.size(); i++) { |
488 | 30 | boolean swap = false; |
489 | 64 | for (int j = 0; j < tmpList.size(); j++) { |
490 | 34 | String type = (String) tmpList.get(j); |
491 | 34 | ValidatorAction a = CommonsValidator.getValidatorAction(type); |
492 | |
|
493 | 34 | List dependencies = a.getDependencyList(); |
494 | 34 | if (dependencies != null && dependencies.size() > 0) { |
495 | 8 | int max = -1; |
496 | 16 | for (int n = 0; n < dependencies.size(); n++) { |
497 | 8 | max = Math.max(max, tmpList.indexOf(dependencies.get(n))); |
498 | |
} |
499 | 8 | if (max > j) { |
500 | 4 | String tmp = (String) tmpList.get(j); |
501 | 4 | tmpList.remove(j); |
502 | 4 | tmpList.add(max, tmp); |
503 | 4 | swap = true; |
504 | 4 | j = max; |
505 | |
} |
506 | |
} |
507 | |
|
508 | |
} |
509 | 30 | if (!swap) { |
510 | 26 | break ordered; |
511 | |
} |
512 | |
} |
513 | |
|
514 | 26 | return tmpList; |
515 | |
|
516 | |
} |
517 | |
|
518 | |
|
519 | |
|
520 | |
|
521 | |
|
522 | |
|
523 | |
|
524 | |
|
525 | |
|
526 | |
|
527 | |
|
528 | |
|
529 | |
public void writeJavaScriptParams(ResponseWriter writer, |
530 | |
FacesContext context, String id, CommonsValidator v) throws IOException { |
531 | |
|
532 | 30 | Map localVars = null; |
533 | |
|
534 | |
|
535 | 30 | if (validatorVars != null && validatorVars.containsKey(id)) { |
536 | |
Map typeVars = (Map) validatorVars.get(id); |
537 | |
if (typeVars != null && typeVars.containsKey(v.getType())) { |
538 | |
localVars = (Map) typeVars.get(v.getType()); |
539 | |
} |
540 | |
} |
541 | |
|
542 | 30 | Tags tagUtils = new Tags(); |
543 | 30 | ValidatorAction validatorAction = v.getValidatorAction(); |
544 | 30 | writer.write("new Array(\""); |
545 | 30 | writer.write(id); |
546 | 30 | writer.write("\", \""); |
547 | 30 | writer.write(v.getErrorMessage(context, validatorAction, localVars)); |
548 | 30 | writer.write("\", new Function(\"x\", \"return {"); |
549 | |
|
550 | 30 | Iterator vi = v.getVars().entrySet().iterator(); |
551 | |
|
552 | 30 | boolean first = true; |
553 | |
|
554 | |
|
555 | |
|
556 | 30 | Map idVars = (Map) validatorVars.get(id); |
557 | |
|
558 | 84 | next: while (vi.hasNext()) { |
559 | 54 | Map.Entry e = (Map.Entry) vi.next(); |
560 | |
|
561 | 54 | Object value = e.getValue(); |
562 | |
|
563 | |
|
564 | 54 | if (idVars != null && idVars.containsKey(v.getType())) { |
565 | |
|
566 | |
Map typeVars = (Map) idVars.get(v.getType()); |
567 | |
|
568 | |
if (typeVars != null && typeVars.containsKey(e.getKey())) { |
569 | |
value = typeVars.get(e.getKey()); |
570 | |
} |
571 | |
} else { |
572 | 54 | if (value != null && value instanceof String |
573 | |
&& isValueReference((String) e.getValue())) { |
574 | |
|
575 | |
value = tagUtils.eval((String) e.getValue()); |
576 | |
} |
577 | |
} |
578 | |
|
579 | 54 | if (value == null) { |
580 | |
continue next; |
581 | |
} |
582 | 54 | String name = (String) e.getKey(); |
583 | 54 | if (!first) { |
584 | 24 | writer.write(","); |
585 | 24 | } else { |
586 | 30 | first = false; |
587 | |
} |
588 | 54 | writer.write(name); |
589 | 54 | writer.write(":"); |
590 | |
|
591 | 54 | String jsType = v.getVarType(name); |
592 | |
|
593 | 54 | if (jsType.equals(Var.JSTYPE_REGEXP)) { |
594 | 2 | writer.write("/"); |
595 | 2 | } else { |
596 | 52 | writer.write("'"); |
597 | |
} |
598 | |
|
599 | 54 | writer.write(escapeJavascript(value.toString())); |
600 | |
|
601 | 54 | if (jsType.equals(Var.JSTYPE_REGEXP)) { |
602 | 2 | writer.write("/"); |
603 | 2 | } else { |
604 | 52 | writer.write("'"); |
605 | |
} |
606 | 54 | } |
607 | 30 | writer.write("}[x];\"))"); |
608 | 30 | } |
609 | |
|
610 | |
|
611 | |
|
612 | |
|
613 | |
|
614 | |
|
615 | |
|
616 | |
|
617 | |
|
618 | |
|
619 | |
|
620 | |
public String findForm(FacesContext context, UIComponent component) { |
621 | |
|
622 | 26 | UIComponent parent = component.getParent(); |
623 | 26 | if (parent != null) { |
624 | 26 | if (parent instanceof UIForm) { |
625 | 26 | return parent.getClientId(context).replace(UINamingContainer.SEPARATOR_CHAR, '_'); |
626 | |
} else { |
627 | |
return findForm(context, parent); |
628 | |
} |
629 | |
} |
630 | |
|
631 | |
return ""; |
632 | |
} |
633 | |
|
634 | |
|
635 | |
|
636 | |
|
637 | |
|
638 | |
|
639 | |
|
640 | |
|
641 | |
|
642 | |
|
643 | |
|
644 | |
|
645 | |
public void encodeBegin(FacesContext context) throws IOException { |
646 | 13 | ResponseWriter writer = context.getResponseWriter(); |
647 | |
|
648 | 13 | validators.clear(); |
649 | 13 | findCommonsValidators(context.getViewRoot(), context); |
650 | |
|
651 | 13 | writeScriptStart(writer); |
652 | 13 | writeValidationFunctions(writer, context); |
653 | 13 | writeScriptEnd(writer); |
654 | 13 | } |
655 | |
|
656 | |
|
657 | |
|
658 | |
|
659 | |
|
660 | |
|
661 | |
|
662 | |
|
663 | |
|
664 | |
|
665 | |
private boolean isValueReference(String value) { |
666 | |
|
667 | 54 | if (value == null) { |
668 | |
return false; |
669 | |
} |
670 | |
|
671 | 54 | int start = value.indexOf("#{"); |
672 | 54 | if (start < 0) { |
673 | 54 | return false; |
674 | |
} |
675 | |
|
676 | |
int end = value.lastIndexOf('}'); |
677 | |
return (end >= 0) && (start < end); |
678 | |
} |
679 | |
|
680 | |
|
681 | |
} |