1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts.faces.taglib;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32
33 import javax.faces.component.UIComponent;
34 import javax.faces.context.FacesContext;
35 import javax.faces.webapp.UIComponentTag;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.jsp.JspException;
38 import javax.servlet.jsp.JspWriter;
39 import javax.servlet.jsp.PageContext;
40 import javax.servlet.jsp.tagext.BodyTagSupport;
41 import javax.servlet.jsp.tagext.Tag;
42 import javax.servlet.ServletContext;
43
44 import org.apache.commons.validator.Field;
45 import org.apache.commons.validator.Form;
46 import org.apache.commons.validator.ValidatorAction;
47 import org.apache.commons.validator.ValidatorResources;
48 import org.apache.commons.validator.Var;
49 import org.apache.commons.validator.util.ValidatorUtils;
50 import org.apache.struts.Globals;
51 import org.apache.struts.config.ModuleConfig;
52 import org.apache.struts.faces.component.FormComponent;
53 import org.apache.struts.taglib.TagUtils;
54 import org.apache.struts.util.MessageResources;
55 import org.apache.struts.util.ModuleUtils;
56 import org.apache.struts.validator.Resources;
57 import org.apache.struts.validator.ValidatorPlugIn;
58
59
60
61
62
63
64
65
66
67
68
69 public class JavascriptValidatorTag extends BodyTagSupport {
70
71
72
73
74
75
76 protected String bundle = Globals.MESSAGES_KEY;
77
78
79
80
81
82 protected static Locale defaultLocale = Locale.getDefault();
83
84
85
86
87
88
89 protected String formName = null;
90
91
92
93
94 protected static String lineEnd = System.getProperty("line.separator");
95
96
97
98
99
100 protected int page = 0;
101
102
103
104
105
106
107 protected String methodName = null;
108
109
110
111
112
113 protected String staticJavascript = "true";
114
115
116
117
118
119 protected String dynamicJavascript = "true";
120
121
122
123
124
125
126 protected String src = null;
127
128
129
130
131
132 protected String htmlComment = "true";
133
134
135
136
137 protected String cdata = "true";
138
139 private String htmlBeginComment = "\n<!-- Begin \n";
140
141 private String htmlEndComment = "//End --> \n";
142
143
144
145
146
147
148 public String getFormName() {
149 return formName;
150 }
151
152
153
154
155
156
157
158
159 public void setFormName(String formName) {
160 this.formName = formName;
161 }
162
163
164
165
166
167
168
169 public int getPage() {
170 return page;
171 }
172
173
174
175
176
177
178
179 public void setPage(int page) {
180 this.page = page;
181 }
182
183
184
185
186
187
188
189 public String getMethod() {
190 return methodName;
191 }
192
193
194
195
196
197
198
199 public void setMethod(String methodName) {
200 this.methodName = methodName;
201 }
202
203
204
205
206
207
208 public String getStaticJavascript() {
209 return staticJavascript;
210 }
211
212
213
214
215
216
217 public void setStaticJavascript(String staticJavascript) {
218 this.staticJavascript = staticJavascript;
219 }
220
221
222
223
224
225
226 public String getDynamicJavascript() {
227 return dynamicJavascript;
228 }
229
230
231
232
233
234
235 public void setDynamicJavascript(String dynamicJavascript) {
236 this.dynamicJavascript = dynamicJavascript;
237 }
238
239
240
241
242
243
244 public String getHtmlComment() {
245 return htmlComment;
246 }
247
248
249
250
251
252
253 public void setHtmlComment(String htmlComment) {
254 this.htmlComment = htmlComment;
255 }
256
257
258
259
260
261 public String getSrc() {
262 return src;
263 }
264
265
266
267
268
269
270 public void setSrc(String src) {
271 this.src = src;
272 }
273
274
275
276
277
278
279 public int doStartTag() throws JspException {
280 StringBuffer results = new StringBuffer();
281
282 HttpServletRequest request =
283 (HttpServletRequest)pageContext.getRequest();
284 ServletContext servletContext = pageContext.getServletContext();
285 ModuleConfig config =
286 ModuleUtils.getInstance().getModuleConfig(request, servletContext);
287
288 ValidatorResources resources =
289 (ValidatorResources) pageContext.getAttribute(
290 ValidatorPlugIn.VALIDATOR_KEY + config.getPrefix(),
291 PageContext.APPLICATION_SCOPE);
292
293 Locale locale = TagUtils.getInstance().getUserLocale(pageContext, null);
294
295 Form form = resources.getForm(locale, formName);
296 if (form != null) {
297 if ("true".equalsIgnoreCase(dynamicJavascript)) {
298 MessageResources messages =
299 (MessageResources) pageContext.getAttribute(
300 bundle + config.getPrefix(),
301 PageContext.APPLICATION_SCOPE);
302
303 List lActions = new ArrayList();
304 List lActionMethods = new ArrayList();
305
306
307 for (Iterator i = form.getFields().iterator(); i.hasNext();) {
308 Field field = (Field) i.next();
309
310 for (Iterator x = field.getDependencyList().iterator();
311 x.hasNext();) {
312 Object o = x.next();
313
314 if (o != null && !lActionMethods.contains(o)) {
315 lActionMethods.add(o);
316 }
317 }
318
319 }
320
321
322 for (Iterator i = lActionMethods.iterator(); i.hasNext();) {
323 String depends = (String) i.next();
324 ValidatorAction va = resources.getValidatorAction(depends);
325
326
327 if (va == null) {
328 throw new NullPointerException(
329 "Depends string \""
330 + depends
331 + "\" was not found in validator-rules.xml.");
332 }
333
334 String javascript = va.getJavascript();
335 if (javascript != null && javascript.length() > 0) {
336 lActions.add(va);
337 } else {
338 i.remove();
339 }
340 }
341
342 Collections.sort(lActions, new Comparator() {
343 public int compare(Object o1, Object o2) {
344 ValidatorAction va1 = (ValidatorAction) o1;
345 ValidatorAction va2 = (ValidatorAction) o2;
346
347 if ((va1.getDepends() == null
348 || va1.getDepends().length() == 0)
349 && (va2.getDepends() == null
350 || va2.getDepends().length() == 0)) {
351 return 0;
352 } else if (
353 (va1.getDepends() != null
354 && va1.getDepends().length() > 0)
355 && (va2.getDepends() == null
356 || va2.getDepends().length() == 0)) {
357 return 1;
358 } else if (
359 (va1.getDepends() == null
360 || va1.getDepends().length() == 0)
361 && (va2.getDepends() != null
362 && va2.getDepends().length() > 0)) {
363 return -1;
364 } else {
365 return va1.getDependencyList().size() -
366 va2.getDependencyList().size();
367 }
368 }
369 });
370
371 String methods = null;
372 for (Iterator i = lActions.iterator(); i.hasNext();) {
373 ValidatorAction va = (ValidatorAction) i.next();
374
375 if (methods == null) {
376 methods = va.getMethod() + "(form)";
377 } else {
378 methods += " && " + va.getMethod() + "(form)";
379 }
380 }
381
382 results.append(getJavascriptBegin(methods));
383
384 for (Iterator i = lActions.iterator(); i.hasNext();) {
385 ValidatorAction va = (ValidatorAction) i.next();
386 String jscriptVar = null;
387 String functionName = null;
388
389 if (va.getJsFunctionName() != null
390 && va.getJsFunctionName().length() > 0) {
391 functionName = va.getJsFunctionName();
392 } else {
393 functionName = va.getName();
394 }
395
396 if (isStruts11()) {
397 results.append(" function " +
398 functionName + " () { \n");
399 } else {
400 results.append(" function " +
401 formName + "_" + functionName +
402 " () { \n");
403 }
404 for (Iterator x = form.getFields().iterator();
405 x.hasNext();) {
406 Field field = (Field) x.next();
407
408
409
410
411 if (field.isIndexed()
412 || field.getPage() != page
413 || !field.isDependency(va.getName())) {
414
415 continue;
416 }
417
418 String message =
419 Resources.getMessage(messages, locale, va, field);
420
421 message = (message != null) ? message : "";
422
423 jscriptVar = this.getNextVar(jscriptVar);
424
425 results.append(
426 " this."
427 + jscriptVar
428 + " = new Array(\""
429 + getFormClientId()
430 + ":"
431 + field.getKey()
432 + "\", \""
433 + message
434 + "\", ");
435
436 results.append("new Function (\"varName\", \"");
437
438 Map vars = field.getVars();
439
440 Iterator varsIterator = vars.keySet().iterator();
441 while (varsIterator.hasNext()) {
442 String varName = (String) varsIterator.next();
443 Var var = (Var) vars.get(varName);
444 String varValue = var.getValue();
445 String jsType = var.getJsType();
446
447
448
449 if (varName.startsWith("field")) {
450 continue;
451 }
452
453 if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) {
454 results.append(
455 "this."
456 + varName
457 + "="
458 + ValidatorUtils.replace(
459 varValue,
460 "\\",
461 "\\\\")
462 + "; ");
463 } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(
464 jsType)) {
465 results.append(
466 "this."
467 + varName
468 + "=/"
469 + ValidatorUtils.replace(
470 varValue,
471 "\\",
472 "\\\\")
473 + "/; ");
474 } else if (Var.JSTYPE_STRING.equalsIgnoreCase(
475 jsType)) {
476 results.append(
477 "this."
478 + varName
479 + "='"
480 + ValidatorUtils.replace(
481 varValue,
482 "\\",
483 "\\\\")
484 + "'; ");
485
486
487 } else if ("mask".equalsIgnoreCase(varName)) {
488 results.append(
489 "this."
490 + varName
491 + "=/"
492 + ValidatorUtils.replace(
493 varValue,
494 "\\",
495 "\\\\")
496 + "/; ");
497 } else {
498 results.append(
499 "this."
500 + varName
501 + "='"
502 + ValidatorUtils.replace(
503 varValue,
504 "\\",
505 "\\\\")
506 + "'; ");
507 }
508 }
509
510 results.append(" return this[varName];\"));\n");
511 }
512 results.append(" } \n\n");
513 }
514 } else if ("true".equalsIgnoreCase(staticJavascript)) {
515 results.append(this.getStartElement());
516 if ("true".equalsIgnoreCase(htmlComment)) {
517 results.append(htmlBeginComment);
518 }
519 }
520 }
521
522 if ("true".equalsIgnoreCase(staticJavascript)) {
523 results.append(getJavascriptStaticMethods(resources));
524 }
525
526 if (form != null
527 && ("true".equalsIgnoreCase(dynamicJavascript)
528 || "true".equalsIgnoreCase(staticJavascript))) {
529
530 results.append(getJavascriptEnd());
531 }
532
533
534 JspWriter writer = pageContext.getOut();
535 try {
536 writer.print(results.toString());
537 } catch (IOException e) {
538 throw new JspException(e.getMessage());
539 }
540
541 return (EVAL_BODY_TAG);
542
543 }
544
545
546
547
548 public void release() {
549 super.release();
550 bundle = Globals.MESSAGES_KEY;
551 formName = null;
552 page = 0;
553 methodName = null;
554 staticJavascript = "true";
555 dynamicJavascript = "true";
556 htmlComment = "true";
557 cdata = "true";
558 src = null;
559 formClientId = null;
560 }
561
562
563
564
565 protected String getJavascriptBegin(String methods) {
566 StringBuffer sb = new StringBuffer();
567 String name =
568 formName.substring(0, 1).toUpperCase()
569 + formName.substring(1, formName.length());
570
571 sb.append(this.getStartElement());
572
573 if (this.isXhtml() && "true".equalsIgnoreCase(this.cdata)) {
574 sb.append("<![CDATA[\r\n");
575 }
576
577 if (!this.isXhtml() && "true".equals(htmlComment)) {
578 sb.append(htmlBeginComment);
579 }
580 sb.append("\n var bCancel = false; \n\n");
581
582 if (methodName == null || methodName.length() == 0) {
583 sb.append(
584 " function validate"
585 + name
586 + "(form) { "
587 + " \n");
588 } else {
589 sb.append(
590 " function "
591 + methodName
592 + "(form) { "
593 + " \n");
594 }
595 sb.append(" if (bCancel) \n");
596 sb.append(" return true; \n");
597 sb.append(" else \n");
598
599
600 if (methods == null || methods.length() == 0) {
601 sb.append(" return true; \n");
602 } else {
603 sb.append(" return " + methods + "; \n");
604 }
605
606 sb.append(" } \n\n");
607
608 return sb.toString();
609 }
610
611 protected String getJavascriptStaticMethods(ValidatorResources resources) {
612 StringBuffer sb = new StringBuffer();
613
614 sb.append("\n\n");
615
616 Iterator actions = resources.getValidatorActions().values().iterator();
617 while (actions.hasNext()) {
618 ValidatorAction va = (ValidatorAction) actions.next();
619 if (va != null) {
620 String javascript = va.getJavascript();
621 if (javascript != null && javascript.length() > 0) {
622 sb.append(javascript + "\n");
623 }
624 }
625 }
626
627 return sb.toString();
628 }
629
630
631
632
633 protected String getJavascriptEnd() {
634 StringBuffer sb = new StringBuffer();
635
636 sb.append("\n");
637 if (!this.isXhtml() && "true".equals(htmlComment)){
638 sb.append(htmlEndComment);
639 }
640
641 if (this.isXhtml() && "true".equalsIgnoreCase(this.cdata)) {
642 sb.append("]]>\r\n");
643 }
644
645 sb.append("</script>\n\n");
646
647 return sb.toString();
648 }
649
650
651
652
653
654 private String getNextVar(String input) {
655 if (input == null) {
656 return "aa";
657 }
658
659 input = input.toLowerCase();
660
661 for (int i = input.length(); i > 0; i--) {
662 int pos = i - 1;
663
664 char c = input.charAt(pos);
665 c++;
666
667 if (c <= 'z') {
668 if (i == 0) {
669 return c + input.substring(pos, input.length());
670 } else if (i == input.length()) {
671 return input.substring(0, pos) + c;
672 } else {
673 return input.substring(0, pos) + c + input.substring(pos,
674 input.length() - 1);
675 }
676 } else {
677 input = replaceChar(input, pos, 'a');
678 }
679
680 }
681
682 return null;
683
684 }
685
686
687
688
689 private String replaceChar(String input, int pos, char c) {
690 if (pos == 0) {
691 return c + input.substring(pos, input.length());
692 } else if (pos == input.length()) {
693 return input.substring(0, pos) + c;
694 } else {
695 return input.substring(0, pos) + c + input.substring(pos,
696 input.length() - 1);
697 }
698 }
699
700
701
702
703
704 private String getStartElement() {
705 StringBuffer start =
706 new StringBuffer("<script type=\"text/javascript\"");
707
708
709 if (!this.isXhtml()) {
710 start.append(" language=\"Javascript1.1\"");
711 }
712
713 if (this.src != null) {
714 start.append(" src=\"" + src + "\"");
715 }
716
717 start.append("> \n");
718 return start.toString();
719 }
720
721
722
723
724 private boolean isXhtml() {
725 return TagUtils.getInstance().isXhtml(this.pageContext);
726 }
727
728
729
730
731
732 public String getCdata() {
733 return cdata;
734 }
735
736
737
738
739
740 public void setCdata(String cdata) {
741 this.cdata = cdata;
742 }
743
744
745 private String formClientId = null;
746
747
748
749
750
751
752
753
754 private String getFormClientId(){
755
756
757 if (formClientId != null) {
758 return (formClientId);
759 }
760
761
762 Tag parent = getParent();
763 while (parent != null) {
764 if (parent instanceof UIComponentTag) {
765 break;
766 }
767 parent = parent.getParent();
768 }
769 if (parent == null) {
770 throw new IllegalArgumentException
771 ("Not nested inside a UIComponentTag");
772 }
773
774
775 UIComponent parentComponent =
776 ((UIComponentTag) parent).getComponentInstance();
777 if (parentComponent instanceof FormComponent) {
778 if (formName.equals(
779 parentComponent.getAttributes().get("beanName"))) {
780 formClientId = parentComponent.getClientId
781 (FacesContext.getCurrentInstance());
782 return (formClientId);
783 }
784 }
785
786
787 Iterator kids = ((UIComponentTag) parent).
788 getComponentInstance().getChildren().iterator();
789 while (kids.hasNext()) {
790 UIComponent kid = (UIComponent) kids.next();
791 if (!(kid instanceof FormComponent)) {
792 continue;
793 }
794 if (formName.equals(kid.getAttributes().get("beanName"))) {
795 formClientId =
796 kid.getClientId(FacesContext.getCurrentInstance());
797 return (formClientId);
798 }
799 }
800 throw new IllegalArgumentException
801 ("Cannot find child FormComponent for form '" + formName + "'");
802
803 }
804
805
806
807
808
809 private static boolean struts11;
810
811 static {
812 try {
813 JavascriptValidatorTag.class.getClassLoader().loadClass
814 ("org.apache.struts.taglib.TagUtils");
815 struts11 = false;
816 } catch (Exception e) {
817 struts11 = true;
818 }
819 }
820
821
822
823
824
825 private static boolean isStruts11() {
826 return struts11;
827 }
828
829
830 }