1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.taglib.html;
19
20 import org.apache.commons.validator.Field;
21 import org.apache.commons.validator.Form;
22 import org.apache.commons.validator.ValidatorAction;
23 import org.apache.commons.validator.ValidatorResources;
24 import org.apache.commons.validator.Var;
25 import org.apache.struts.Globals;
26 import org.apache.struts.action.ActionMapping;
27 import org.apache.struts.config.ModuleConfig;
28 import org.apache.struts.taglib.TagUtils;
29 import org.apache.struts.util.MessageResources;
30 import org.apache.struts.validator.Resources;
31 import org.apache.struts.validator.ValidatorPlugIn;
32
33 import javax.servlet.ServletContext;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.jsp.JspException;
36 import javax.servlet.jsp.JspWriter;
37 import javax.servlet.jsp.PageContext;
38 import javax.servlet.jsp.tagext.BodyTagSupport;
39
40 import java.io.IOException;
41
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.Comparator;
45 import java.util.Iterator;
46 import java.util.List;
47 import java.util.Locale;
48 import java.util.Map;
49 import java.util.StringTokenizer;
50
51 /***
52 * Custom tag that generates JavaScript for client side validation based on
53 * the validation rules loaded by the <code>ValidatorPlugIn</code> defined in
54 * the struts-config.xml file.
55 *
56 * @version $Rev: 421129 $ $Date: 2006-07-11 22:13:54 -0700 (Tue, 11 Jul 2006) $
57 * @since Struts 1.1
58 */
59 public class JavascriptValidatorTag extends BodyTagSupport {
60 /***
61 * A Comparator to use when sorting ValidatorAction objects.
62 */
63 private static final Comparator actionComparator =
64 new Comparator() {
65 public int compare(Object o1, Object o2) {
66 ValidatorAction va1 = (ValidatorAction) o1;
67 ValidatorAction va2 = (ValidatorAction) o2;
68
69 if (((va1.getDepends() == null)
70 || (va1.getDepends().length() == 0))
71 && ((va2.getDepends() == null)
72 || (va2.getDepends().length() == 0))) {
73 return 0;
74 } else if (((va1.getDepends() != null)
75 && (va1.getDepends().length() > 0))
76 && ((va2.getDepends() == null)
77 || (va2.getDepends().length() == 0))) {
78 return 1;
79 } else if (((va1.getDepends() == null)
80 || (va1.getDepends().length() == 0))
81 && ((va2.getDepends() != null)
82 && (va2.getDepends().length() > 0))) {
83 return -1;
84 } else {
85 return va1.getDependencyList().size()
86 - va2.getDependencyList().size();
87 }
88 }
89 };
90
91 /***
92 * The start of the HTML comment hiding JavaScript from old browsers.
93 *
94 * @since Struts 1.2
95 */
96 protected static final String HTML_BEGIN_COMMENT = "\n<!-- Begin \n";
97
98 /***
99 * The end of the HTML comment hiding JavaScript from old browsers.
100 *
101 * @since Struts 1.2
102 */
103 protected static final String HTML_END_COMMENT = "//End --> \n";
104
105 /***
106 * The line ending string.
107 */
108 protected static String lineEnd = System.getProperty("line.separator");
109
110
111
112 /***
113 * The servlet context attribute key for our resources.
114 */
115 protected String bundle = Globals.MESSAGES_KEY;
116
117 /***
118 * The name of the form that corresponds with the action name in
119 * struts-config.xml. Specifying a form name places a <script>
120 * </script> around the javascript.
121 */
122 protected String formName = null;
123
124 /***
125 * formName is used for both Javascript and non-javascript validations.
126 * For the javascript validations, there is the possibility that we will
127 * be rewriting the formName (if it is a ValidatorActionForm instead of
128 * just a ValidatorForm) so we need another variable to hold the formName
129 * just for javascript usage.
130 */
131 protected String jsFormName = null;
132
133 /***
134 * The current page number of a multi-part form. Only valid when the
135 * formName attribute is set.
136 */
137 protected int page = 0;
138
139 /***
140 * This will be used as is for the JavaScript validation method name if it
141 * has a value. This is the method name of the main JavaScript method
142 * that the form calls to perform validations.
143 */
144 protected String methodName = null;
145
146 /***
147 * Include language attribute in the <script> element. This
148 * property is ignored in XHTML mode.
149 *
150 * @since Struts 1.2
151 */
152 protected boolean scriptLanguage = true;
153
154 /***
155 * The static JavaScript methods will only be printed if this is set to
156 * "true".
157 */
158 protected String staticJavascript = "true";
159
160 /***
161 * The dynamic JavaScript objects will only be generated if this is set to
162 * "true".
163 */
164 protected String dynamicJavascript = "true";
165
166 /***
167 * The src attribute for html script element (used to include an external
168 * script resource). The src attribute is only recognized when the
169 * formName attribute is specified.
170 */
171 protected String src = null;
172
173 /***
174 * The JavaScript methods will enclosed with html comments if this is set
175 * to "true".
176 */
177 protected String htmlComment = "true";
178
179 /***
180 * Hide JavaScript methods in a CDATA section for XHTML when "true".
181 */
182 protected String cdata = "true";
183
184 /***
185 * Gets the key (form name) that will be used to retrieve a set of
186 * validation rules to be performed on the bean passed in for validation.
187 */
188 public String getFormName() {
189 return formName;
190 }
191
192 /***
193 * Sets the key (form name) that will be used to retrieve a set of
194 * validation rules to be performed on the bean passed in for validation.
195 * Specifying a form name places a <script> </script> tag
196 * around the javascript.
197 */
198 public void setFormName(String formName) {
199 this.formName = formName;
200 }
201
202 /***
203 * @return Returns the jsFormName.
204 */
205 public String getJsFormName() {
206 return jsFormName;
207 }
208
209 /***
210 * @param jsFormName The jsFormName to set.
211 */
212 public void setJsFormName(String jsFormName) {
213 this.jsFormName = jsFormName;
214 }
215
216 /***
217 * Gets the current page number of a multi-part form. Only field
218 * validations with a matching page numer will be generated that match the
219 * current page number. Only valid when the formName attribute is set.
220 */
221 public int getPage() {
222 return page;
223 }
224
225 /***
226 * Sets the current page number of a multi-part form. Only field
227 * validations with a matching page numer will be generated that match the
228 * current page number. Only valid when the formName attribute is set.
229 */
230 public void setPage(int page) {
231 this.page = page;
232 }
233
234 /***
235 * Gets the method name that will be used for the Javascript validation
236 * method name if it has a value. This overrides the auto-generated
237 * method name based on the key (form name) passed in.
238 */
239 public String getMethod() {
240 return methodName;
241 }
242
243 /***
244 * Sets the method name that will be used for the Javascript validation
245 * method name if it has a value. This overrides the auto-generated
246 * method name based on the key (form name) passed in.
247 */
248 public void setMethod(String methodName) {
249 this.methodName = methodName;
250 }
251
252 /***
253 * Gets whether or not to generate the static JavaScript. If this is set
254 * to 'true', which is the default, the static JavaScript will be
255 * generated.
256 */
257 public String getStaticJavascript() {
258 return staticJavascript;
259 }
260
261 /***
262 * Sets whether or not to generate the static JavaScript. If this is set
263 * to 'true', which is the default, the static JavaScript will be
264 * generated.
265 */
266 public void setStaticJavascript(String staticJavascript) {
267 this.staticJavascript = staticJavascript;
268 }
269
270 /***
271 * Gets whether or not to generate the dynamic JavaScript. If this is set
272 * to 'true', which is the default, the dynamic JavaScript will be
273 * generated.
274 */
275 public String getDynamicJavascript() {
276 return dynamicJavascript;
277 }
278
279 /***
280 * Sets whether or not to generate the dynamic JavaScript. If this is set
281 * to 'true', which is the default, the dynamic JavaScript will be
282 * generated.
283 */
284 public void setDynamicJavascript(String dynamicJavascript) {
285 this.dynamicJavascript = dynamicJavascript;
286 }
287
288 /***
289 * Gets whether or not to delimit the JavaScript with html comments. If
290 * this is set to 'true', which is the default, the htmlComment will be
291 * surround the JavaScript.
292 */
293 public String getHtmlComment() {
294 return htmlComment;
295 }
296
297 /***
298 * Sets whether or not to delimit the JavaScript with html comments. If
299 * this is set to 'true', which is the default, the htmlComment will be
300 * surround the JavaScript.
301 */
302 public void setHtmlComment(String htmlComment) {
303 this.htmlComment = htmlComment;
304 }
305
306 /***
307 * Gets the src attribute's value when defining the html script element.
308 */
309 public String getSrc() {
310 return src;
311 }
312
313 /***
314 * Sets the src attribute's value when defining the html script element.
315 * The src attribute is only recognized when the formName attribute is
316 * specified.
317 */
318 public void setSrc(String src) {
319 this.src = src;
320 }
321
322 /***
323 * Sets the servlet context attribute key for our resources.
324 */
325 public String getBundle() {
326 return bundle;
327 }
328
329 /***
330 * Gets the servlet context attribute key for our resources.
331 */
332 public void setBundle(String bundle) {
333 this.bundle = bundle;
334 }
335
336 /***
337 * Render the JavaScript for to perform validations based on the form
338 * name.
339 *
340 * @throws JspException if a JSP exception has occurred
341 */
342 public int doStartTag() throws JspException {
343 JspWriter writer = pageContext.getOut();
344
345 try {
346 writer.print(this.renderJavascript());
347 } catch (IOException e) {
348 throw new JspException(e.getMessage());
349 }
350
351 return EVAL_BODY_TAG;
352 }
353
354 /***
355 * Returns fully rendered JavaScript.
356 *
357 * @since Struts 1.2
358 */
359 protected String renderJavascript()
360 throws JspException {
361 StringBuffer results = new StringBuffer();
362
363 ModuleConfig config =
364 TagUtils.getInstance().getModuleConfig(pageContext);
365 ValidatorResources resources =
366 (ValidatorResources) pageContext.getAttribute(
367 ValidatorPlugIn.VALIDATOR_KEY
368 + config.getPrefix(), PageContext.APPLICATION_SCOPE);
369
370 if (resources == null) {
371 throw new JspException(
372 "ValidatorResources not found in application scope under key \""
373 + ValidatorPlugIn.VALIDATOR_KEY + config.getPrefix() + "\"");
374 }
375
376 Locale locale =
377 TagUtils.getInstance().getUserLocale(this.pageContext, null);
378
379 Form form = null;
380 if ("true".equalsIgnoreCase(dynamicJavascript)) {
381 form = resources.getForm(locale, formName);
382 if (form == null) {
383 throw new JspException("No form found under '" + formName
384 + "' in locale '" + locale
385 + "'. A form must be defined in the "
386 + "Commons Validator configuration when "
387 + "dynamicJavascript=\"true\" is set.");
388 }
389 }
390
391 if (form != null) {
392 if ("true".equalsIgnoreCase(dynamicJavascript)) {
393 results.append(this.createDynamicJavascript(config, resources,
394 locale, form));
395 } else if ("true".equalsIgnoreCase(staticJavascript)) {
396 results.append(this.renderStartElement());
397
398 if ("true".equalsIgnoreCase(htmlComment)) {
399 results.append(HTML_BEGIN_COMMENT);
400 }
401 }
402 }
403
404 if ("true".equalsIgnoreCase(staticJavascript)) {
405 results.append(getJavascriptStaticMethods(resources));
406 }
407
408 if ((form != null)
409 && ("true".equalsIgnoreCase(dynamicJavascript)
410 || "true".equalsIgnoreCase(staticJavascript))) {
411 results.append(getJavascriptEnd());
412 }
413
414 return results.toString();
415 }
416
417 /***
418 * Generates the dynamic JavaScript for the form.
419 *
420 * @param config
421 * @param resources
422 * @param locale
423 * @param form
424 */
425 private String createDynamicJavascript(ModuleConfig config,
426 ValidatorResources resources, Locale locale, Form form)
427 throws JspException {
428 StringBuffer results = new StringBuffer();
429
430 MessageResources messages =
431 TagUtils.getInstance().retrieveMessageResources(pageContext,
432 bundle, true);
433
434 HttpServletRequest request =
435 (HttpServletRequest) pageContext.getRequest();
436 ServletContext application = pageContext.getServletContext();
437
438 List actions = this.createActionList(resources, form);
439
440 final String methods =
441 this.createMethods(actions, this.stopOnError(config));
442
443 String formName = form.getName();
444
445 jsFormName = formName;
446
447 if (jsFormName.charAt(0) == '/') {
448 String mappingName =
449 TagUtils.getInstance().getActionMappingName(jsFormName);
450 ActionMapping mapping =
451 (ActionMapping) config.findActionConfig(mappingName);
452
453 if (mapping == null) {
454 JspException e =
455 new JspException(messages.getMessage("formTag.mapping",
456 mappingName));
457
458 pageContext.setAttribute(Globals.EXCEPTION_KEY, e,
459 PageContext.REQUEST_SCOPE);
460 throw e;
461 }
462
463 jsFormName = mapping.getAttribute();
464 }
465
466 results.append(this.getJavascriptBegin(methods));
467
468 for (Iterator i = actions.iterator(); i.hasNext();) {
469 ValidatorAction va = (ValidatorAction) i.next();
470 int jscriptVar = 0;
471 String functionName = null;
472
473 if ((va.getJsFunctionName() != null)
474 && (va.getJsFunctionName().length() > 0)) {
475 functionName = va.getJsFunctionName();
476 } else {
477 functionName = va.getName();
478 }
479
480 results.append(" function " + jsFormName + "_" + functionName
481 + " () { \n");
482
483 for (Iterator x = form.getFields().iterator(); x.hasNext();) {
484 Field field = (Field) x.next();
485
486
487
488
489 if (field.isIndexed() || (field.getPage() != page)
490 || !field.isDependency(va.getName())) {
491 continue;
492 }
493
494 String message =
495 Resources.getMessage(application, request, messages,
496 locale, va, field);
497
498 message = (message != null) ? message : "";
499
500
501 results.append(" this.a" + jscriptVar++ + " = new Array(\""
502 + field.getKey() + "\", \"" + escapeQuotes(message)
503 + "\", ");
504
505 results.append("new Function (\"varName\", \"");
506
507 Map vars = field.getVars();
508
509
510 Iterator varsIterator = vars.keySet().iterator();
511
512 while (varsIterator.hasNext()) {
513 String varName = (String) varsIterator.next();
514 Var var = (Var) vars.get(varName);
515 String varValue =
516 Resources.getVarValue(var, application, request, false);
517 String jsType = var.getJsType();
518
519
520
521 if (varName.startsWith("field")) {
522 continue;
523 }
524
525 String varValueEscaped = escapeJavascript(varValue);
526
527 if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) {
528 results.append("this." + varName + "="
529 + varValueEscaped + "; ");
530 } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) {
531 results.append("this." + varName + "=/"
532 + varValueEscaped + "/; ");
533 } else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) {
534 results.append("this." + varName + "='"
535 + varValueEscaped + "'; ");
536
537
538
539 } else if ("mask".equalsIgnoreCase(varName)) {
540 results.append("this." + varName + "=/"
541 + varValueEscaped + "/; ");
542 } else {
543 results.append("this." + varName + "='"
544 + varValueEscaped + "'; ");
545 }
546 }
547
548 results.append(" return this[varName];\"));\n");
549 }
550
551 results.append(" } \n\n");
552 }
553
554 return results.toString();
555 }
556
557 private String escapeQuotes(String in) {
558 if ((in == null) || (in.indexOf("\"") == -1)) {
559 return in;
560 }
561
562 StringBuffer buffer = new StringBuffer();
563 StringTokenizer tokenizer = new StringTokenizer(in, "\"", true);
564
565 while (tokenizer.hasMoreTokens()) {
566 String token = tokenizer.nextToken();
567
568 if (token.equals("\"")) {
569 buffer.append("//");
570 }
571
572 buffer.append(token);
573 }
574
575 return buffer.toString();
576 }
577
578 /***
579 * <p>Backslash-escapes the following characters from the input string:
580 * ", ', \, \r, \n.</p>
581 *
582 * <p>This method escapes characters that will result in an invalid
583 * Javascript statement within the validator Javascript.</p>
584 *
585 * @param str The string to escape.
586 * @return The string <code>s</code> with each instance of a double quote,
587 * single quote, backslash, carriage-return, or line feed escaped
588 * with a leading backslash.
589 */
590 private String escapeJavascript(String str) {
591 if (str == null) {
592 return null;
593 }
594
595 int length = str.length();
596
597 if (length == 0) {
598 return str;
599 }
600
601
602 StringBuffer out = new StringBuffer(length + 4);
603
604
605 for (int i = 0; i < length; i++) {
606 char c = str.charAt(i);
607
608 if ((c == '"') || (c == '\'') || (c == '//') || (c == '\n')
609 || (c == '\r')) {
610 out.append('//');
611 }
612
613 out.append(c);
614 }
615
616 return out.toString();
617 }
618
619 /***
620 * Determines if validations should stop on an error.
621 *
622 * @param config The <code>ModuleConfig</code> used to lookup the
623 * stopOnError setting.
624 * @return <code>true</code> if validations should stop on errors.
625 */
626 private boolean stopOnError(ModuleConfig config) {
627 Object stopOnErrorObj =
628 pageContext.getAttribute(ValidatorPlugIn.STOP_ON_ERROR_KEY + '.'
629 + config.getPrefix(), PageContext.APPLICATION_SCOPE);
630
631 boolean stopOnError = true;
632
633 if (stopOnErrorObj instanceof Boolean) {
634 stopOnError = ((Boolean) stopOnErrorObj).booleanValue();
635 }
636
637 return stopOnError;
638 }
639
640 /***
641 * Creates the JavaScript methods list from the given actions.
642 *
643 * @param actions A List of ValidatorAction objects.
644 * @param stopOnError If true, behaves like released version of struts 1.1
645 * and stops after first error. If false, evaluates all
646 * validations.
647 * @return JavaScript methods.
648 */
649 private String createMethods(List actions, boolean stopOnError) {
650 StringBuffer methods = new StringBuffer();
651 final String methodOperator = stopOnError ? " && " : " & ";
652
653 Iterator iter = actions.iterator();
654
655 while (iter.hasNext()) {
656 ValidatorAction va = (ValidatorAction) iter.next();
657
658 if (methods.length() > 0) {
659 methods.append(methodOperator);
660 }
661
662 methods.append(va.getMethod()).append("(form)");
663 }
664
665 return methods.toString();
666 }
667
668 /***
669 * Get List of actions for the given Form.
670 *
671 * @param resources
672 * @param form
673 * @return A sorted List of ValidatorAction objects.
674 */
675 private List createActionList(ValidatorResources resources, Form form) {
676 List actionMethods = new ArrayList();
677
678 Iterator iterator = form.getFields().iterator();
679
680 while (iterator.hasNext()) {
681 Field field = (Field) iterator.next();
682
683 for (Iterator x = field.getDependencyList().iterator();
684 x.hasNext();) {
685 Object o = x.next();
686
687 if ((o != null) && !actionMethods.contains(o)) {
688 actionMethods.add(o);
689 }
690 }
691 }
692
693 List actions = new ArrayList();
694
695
696 iterator = actionMethods.iterator();
697
698 while (iterator.hasNext()) {
699 String depends = (String) iterator.next();
700 ValidatorAction va = resources.getValidatorAction(depends);
701
702
703 if (va == null) {
704 throw new NullPointerException("Depends string \"" + depends
705 + "\" was not found in validator-rules.xml.");
706 }
707
708 if ((va.getJavascript() != null)
709 && (va.getJavascript().length() > 0)) {
710 actions.add(va);
711 } else {
712 iterator.remove();
713 }
714 }
715
716 Collections.sort(actions, actionComparator);
717
718 return actions;
719 }
720
721 /***
722 * Release any acquired resources.
723 */
724 public void release() {
725 super.release();
726 bundle = Globals.MESSAGES_KEY;
727 formName = null;
728 jsFormName = null;
729 page = 0;
730 methodName = null;
731 staticJavascript = "true";
732 dynamicJavascript = "true";
733 htmlComment = "true";
734 cdata = "true";
735 src = null;
736 }
737
738 /***
739 * Returns the opening script element and some initial javascript.
740 */
741 protected String getJavascriptBegin(String methods) {
742 StringBuffer sb = new StringBuffer();
743 String name = jsFormName.replace('/', '_');
744
745 name =
746 jsFormName.substring(0, 1).toUpperCase()
747 + jsFormName.substring(1, jsFormName.length());
748
749 sb.append(this.renderStartElement());
750
751 if (this.isXhtml() && "true".equalsIgnoreCase(this.cdata)) {
752 sb.append("//<![CDATA[\r\n");
753 }
754
755 if (!this.isXhtml() && "true".equals(htmlComment)) {
756 sb.append(HTML_BEGIN_COMMENT);
757 }
758
759 sb.append("\n var bCancel = false; \n\n");
760
761 if ((methodName == null) || (methodName.length() == 0)) {
762 sb.append(" function validate" + name + "(form) { \n");
763 } else {
764 sb.append(" function " + methodName + "(form) { \n");
765 }
766
767 sb.append(" if (bCancel) { \n");
768 sb.append(" return true; \n");
769 sb.append(" } else { \n");
770
771
772 if ((methods == null) || (methods.length() == 0)) {
773 sb.append(" return true; \n");
774 } else {
775 sb.append(" var formValidationResult; \n");
776 sb.append(" formValidationResult = " + methods + "; \n");
777 if (methods.indexOf("&&") >= 0) {
778 sb.append(" return (formValidationResult); \n");
779 } else {
780
781 sb.append(" return (formValidationResult == 1); \n");
782 }
783 }
784 sb.append(" } \n");
785 sb.append(" } \n\n");
786
787 return sb.toString();
788 }
789
790 protected String getJavascriptStaticMethods(ValidatorResources resources) {
791 StringBuffer sb = new StringBuffer();
792
793 sb.append("\n\n");
794
795 Iterator actions = resources.getValidatorActions().values().iterator();
796
797 while (actions.hasNext()) {
798 ValidatorAction va = (ValidatorAction) actions.next();
799
800 if (va != null) {
801 String javascript = va.getJavascript();
802
803 if ((javascript != null) && (javascript.length() > 0)) {
804 sb.append(javascript + "\n");
805 }
806 }
807 }
808
809 return sb.toString();
810 }
811
812 /***
813 * Returns the closing script element.
814 */
815 protected String getJavascriptEnd() {
816 StringBuffer sb = new StringBuffer();
817
818 sb.append("\n");
819
820 if (!this.isXhtml() && "true".equals(htmlComment)) {
821 sb.append(HTML_END_COMMENT);
822 }
823
824 if (this.isXhtml() && "true".equalsIgnoreCase(this.cdata)) {
825 sb.append("//]]>\r\n");
826 }
827
828 sb.append("</script>\n\n");
829
830 return sb.toString();
831 }
832
833 /***
834 * Constructs the beginning <script> element depending on XHTML
835 * status.
836 *
837 * @since Struts 1.2
838 */
839 protected String renderStartElement() {
840 StringBuffer start =
841 new StringBuffer("<script type=\"text/javascript\"");
842
843
844 if (!this.isXhtml() && this.scriptLanguage) {
845 start.append(" language=\"Javascript1.1\"");
846 }
847
848 if (this.src != null) {
849 start.append(" src=\"" + src + "\"");
850 }
851
852 start.append("> \n");
853
854 return start.toString();
855 }
856
857 /***
858 * Returns true if this is an xhtml page.
859 */
860 private boolean isXhtml() {
861 return TagUtils.getInstance().isXhtml(this.pageContext);
862 }
863
864 /***
865 * Returns the cdata setting "true" or "false".
866 *
867 * @return String - "true" if JavaScript will be hidden in a CDATA
868 * section
869 */
870 public String getCdata() {
871 return cdata;
872 }
873
874 /***
875 * Sets the cdata status.
876 *
877 * @param cdata The cdata to set
878 */
879 public void setCdata(String cdata) {
880 this.cdata = cdata;
881 }
882
883 /***
884 * Gets whether or not the <script> element will include the
885 * language attribute.
886 *
887 * @return true if language attribute will be included.
888 * @since Struts 1.2
889 */
890 public boolean getScriptLanguage() {
891 return this.scriptLanguage;
892 }
893
894 /***
895 * Sets whether or not the <script> element will include the
896 * language attribute.
897 *
898 * @since Struts 1.2
899 */
900 public void setScriptLanguage(boolean scriptLanguage) {
901 this.scriptLanguage = scriptLanguage;
902 }
903 }