View Javadoc

1   /*
2    * Copyright 2004-2009 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springmodules.validation.valang.javascript.taglib;
18  
19  import java.io.IOException;
20  import java.io.Reader;
21  import java.io.Writer;
22  
23  import javax.servlet.ServletException;
24  import javax.servlet.jsp.JspException;
25  import javax.servlet.jsp.JspWriter;
26  
27  import org.springframework.util.Assert;
28  import org.springframework.web.servlet.tags.RequestContextAwareTag;
29  import org.springmodules.validation.valang.javascript.ValangJavaScriptTranslator;
30  
31  /**
32   * Generates the JavaScript codebase that is necessary for the use of the
33   * JavaScript validation produced by {@link ValangValidateTag}.
34   * <p/>
35   * <p>The generated codebase is an exact copy of the code from the file
36   * "valang_codebase.js" located in
37   * org.springmodules.validation.valang.javascript. You can therefor avoid having to
38   * use this tag by simply placing this file on your web server and linking
39   * to it using a the following HTML:
40   * <pre>
41   * &lt;script type="text/javascript" src="/somepath/valang_codebase.js"&gt;&lt;/script&gt;
42   * </pre>
43   * <p/>
44   * <p>When using this tag or the HTML above you must make sure that the
45   * codebase is included before any {@link ValangValidateTag}s in you JSP file.
46   *
47   * @author Oliver Hutchison
48   */
49  public class ValangCodebaseTag extends RequestContextAwareTag {
50  
51      private final static String DEFAULT_GLOBAL_ERRORS_ID = "global_errors";
52  
53      private final static String DEFAULT_FIELD_ERROR_ID_SUFFIX = "_error";
54  
55      private boolean includeScriptTags;
56  
57      private String globalErrorsId = DEFAULT_GLOBAL_ERRORS_ID;
58  
59      private String fieldErrorsIdSuffix = DEFAULT_FIELD_ERROR_ID_SUFFIX;
60  
61      /**
62       * Sets whether or not the generated code should be wrapped in HTML
63       * &lt;script&gt; tags. This is useful if you wont to include the
64       * codebase directly in a HTML page.
65       */
66      public void setIncludeScriptTags(String includeScriptTags) {
67          this.includeScriptTags = "true".equalsIgnoreCase(includeScriptTags);
68      }
69  
70      /**
71       * Sets the id of the element that will hold the global error. If not set, this tag will look for
72       * an element with id "global_errors".
73       *
74       * @param globalErrorsId The id of the element that should hold the global errors.
75       */
76      public void setGlobalErrorsId(String globalErrorsId) {
77          this.globalErrorsId = globalErrorsId;
78      }
79  
80      /**
81       * Sets the id suffix of the element that should hold the error of a specific field. For example, if the
82       * validated field is "firstName" and the suffix is set to "_err" then this tag will put the validation
83       * errors for the firstName field in an element with id "firstName_err". If this suffix is not set, it is set
84       * by default to "_error".
85       *
86       * @param fieldErrorsIdSuffix The id suffix of the element that should hold the error of a specific field.
87       */
88      public void setFieldErrorsIdSuffix(String fieldErrorsIdSuffix) {
89          this.fieldErrorsIdSuffix = fieldErrorsIdSuffix;
90      }
91  
92      protected int doStartTagInternal() throws ServletException, JspException {
93          return SKIP_BODY;
94      }
95  
96      public int doEndTag() throws JspException {
97          try {
98              JspWriter out = pageContext.getOut();
99              if (includeScriptTags) {
100                 out.write("<script type=\"text/javascript\">\n");
101             }
102             out.write("var globalErrorsId = '" + globalErrorsId + "';\n");
103             out.write("var fieldErrorIdSuffix = '" + fieldErrorsIdSuffix + "';\n");
104             copy(ValangJavaScriptTranslator.getCodebaseReader(), out);
105             if (includeScriptTags) {
106                 out.write("\n</script>");
107             }
108             return EVAL_PAGE;
109         }
110         catch (IOException e) {
111             throw new JspException("Could not write validation codebase", e);
112         }
113     }
114 
115     /**
116      * Copies the chars from in to out and then closes in but
117      * leaves out open.
118      */
119     private void copy(Reader in, Writer out) throws IOException {
120         Assert.notNull(in, "No Reader specified");
121         Assert.notNull(out, "No Writer specified");
122         try {
123             char[] buffer = new char[1024];
124             int bytesRead;
125             while ((bytesRead = in.read(buffer)) != -1) {
126                 out.write(buffer, 0, bytesRead);
127             }
128             out.flush();
129         }
130         finally {
131             try {
132                 in.close();
133             }
134             catch (IOException ex) {
135                 logger.warn("Could not close Reader", ex);
136             }
137         }
138     }
139 
140     public void doFinally() {
141         super.doFinally();
142         includeScriptTags = false;
143     }
144 }