001 // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org)
002 // The Molly framework is freely distributable under the terms of an
003 // MIT-style license. For details, see the molly pages web site at:
004 // http://www.mollypages.org/. Use, modify, have fun !
005
006 package fc.web.simpleforms;
007
008 import javax.servlet.*;
009 import javax.servlet.http.*;
010 import java.io.*;
011 import java.util.*;
012
013 import fc.io.*;
014
015 /**
016 Convenience class to store arbitrary form validation errors
017 and messages. This class should be instantiated per request
018 as needed (when there are form validation errors).
019 <p>
020 Note: This class is not thread-safe but that's not a concern
021 since only each seperate user request is handled by at
022 most 1 thread.
023
024 @author hursh jain
025 **/
026 public final class Errors
027 {
028 Log log = Log.getDefault();
029
030 List formErrors;
031 Map fieldErrors;
032 List formWarnings;
033 Map fieldWarnings;
034
035 /**
036 Adds a form level error, typically associated with the form
037 itself and/or multiple fields as a group.
038 */
039 public void addFormError(String msg)
040 {
041 if (formErrors == null)
042 formErrors = new ArrayList();
043
044 formErrors.add(msg);
045 }
046
047 /**
048 Adds a field validation error
049
050 @param fieldName the name of the field
051 @param msg some error object, typically a string but
052 can be a list of strings (for example) if
053 there is more than 1 validation error for
054 this field
055 */
056 public void addFieldError(String fieldName, Object msg)
057 {
058 if (fieldErrors == null)
059 fieldErrors = new HashMap();
060
061 Object old = fieldErrors.put(fieldName, msg);
062 if (old != null) {
063 log.warn("Use a list to add more than 1 message. I am currently over-writing the previous error message for field: " + fieldName + " [old msg=" + old + "] [new msg=" + msg + "]");
064 }
065 }
066
067 /**
068 Adds an arbitrary warning message generated as part of form processing
069 */
070 public void addFormWarning(String msg)
071 {
072 if (formWarnings == null)
073 formWarnings = new ArrayList();
074
075 formWarnings.add(msg);
076 }
077
078 /**
079 Adds an arbitrary warning message generated as part of form
080 processing. This warning is associated with the specified field.
081 */
082 public void addFieldWarning(String fieldname, Object msg)
083 {
084 if (fieldWarnings == null)
085 fieldWarnings = new HashMap();
086
087 Object old = fieldWarnings.put(fieldname, msg);
088 if (old != null) {
089 log.warn("Use a list to add more than 1 warning. I am currently over-writing the previous warning message for field: " + fieldname + " [old msg=" + old + "] [new msg=" + msg + "]");
090 }
091 }
092
093 /**
094 Returns a list of all form errors or null if no errors are present.
095 */
096 public List getFormErrors() {
097 return formErrors;
098 }
099
100 /**
101 Returns the field error for the specified fieldname or null if no
102 error was found.
103 */
104 public Object getFieldError(String fieldName)
105 {
106 if (fieldErrors == null)
107 return null;
108
109 return fieldErrors.get(fieldName);
110 }
111
112 /**
113 Returns the list of all form-level warnings or <tt>null</tt> if no
114 warnings exist for the form.
115 */
116 public List getFormWarnings() {
117 return formWarnings;
118 }
119
120 /**
121 Returns the warning for the specified field or <tt>null</tt> if
122 no warning exists.
123 */
124 public Object getFieldWarning(String fieldname) {
125 return fieldWarnings.get(fieldname);
126 }
127
128 /**
129 Returns true if there are any form or field errors. (although
130 warnings are allowed)
131 */
132 public boolean hasError() {
133 return formErrors != null || fieldErrors != null;
134 }
135
136 /**
137 Returns true if there are any warnings.
138 */
139 public boolean hasWarning() {
140 return formWarnings != null || fieldWarnings != null;
141 }
142
143 /**
144 Returns true if there are any warnings for the specified <u>field</u>
145 */
146 public boolean hasWarning(String fieldname) {
147 return fieldWarnings != null && fieldWarnings.containsKey(fieldname);
148 }
149
150
151 /**
152 Convenience method to render all the form errors (if present).
153 For more control, obtain the form errors and print them manually.
154 Invoking this method has the following effect:
155 <blockquote><pre>
156 String after = "<br>";
157 List list = error.getFormErrors();
158 if (list != null)
159 {
160 out.write("<div class='form-errmsg'>");
161 out.write("<ul>");
162 for (int n = 0; n < list.size(); n++) {
163 out.write("<li>");
164 out.write(String.valueOf(list.get(n)));
165 out.write("</li>");
166 }
167 out.write("</ul>");
168 out.write("</div>\n");
169 }
170 </pre></blockquote>
171 */
172 public void renderFormErrors(Writer out) throws IOException
173 {
174 if (formErrors == null) {
175 return;
176 }
177
178 if (formErrors == null)
179 return;
180
181 out.write("<div class='form-errmsg'>");
182 out.write("\n<ul>");
183
184 for (int n = 0; n < formErrors.size(); n++) {
185 Object obj = formErrors.get(n);
186 out.write("<li>");
187 out.write(String.valueOf(obj));
188 out.write("</li>\n");
189 }
190
191 out.write("</ul>\n");
192 out.write("</div>");
193 }
194
195 /**
196 Convenience method to render a field error. Invoking this
197 method is a shorthand for saying (where <tt>error</tt> is
198 an instance of this class):
199 <blockquote><pre>
200 Object obj = error.getFieldError("some_field_name");
201 if (str != null) {
202 out.write("<span class='field-errmsg'>");
203 out.write (String.valueOf(obj));
204 out.write("</span>\n");
205 out.write("<br>");
206 }
207 </pre></blockquote>
208 The above is the same as:
209 <blockquote><pre>
210 error.<font color=blue>render</font>(out, "some_field_name");
211 </pre></blockquote>
212 Note: The object representing the error for the field is written as
213 is. Typically for strings, this works fine. However, for more complex
214 objects (like say a list holding more than 1 error for the same field),
215 the list is printed as-is. For more formatting options for complex
216 objects, obtain and print the error manually.
217 */
218 public void render(Writer out, String fieldName) throws IOException
219 {
220 if (fieldErrors == null) {
221 return;
222 }
223
224 Object obj = fieldErrors.get(fieldName);
225 if (obj == null)
226 return;
227
228 out.write("<span class='field-errmsg'>");
229 out.write(String.valueOf(obj));
230 out.write("</span>");
231 out.write("<br>");
232 }
233
234
235 /**
236 Convenience method to render a field error. Invoking this
237 method is a shorthand for saying (where <tt>error</tt> is
238 an instance of this class):
239 <blockquote><pre>
240 Object obj = error.getFieldError("some_field_name");
241 if (str != null) {
242 out.write("<span class='field-errmsg'>");
243 out.write (String.valueOf(obj));
244 out.write(<font color=blue>"inside"</font>);
245 out.write("</span>\n");
246 out.write(<font color=blue>"outside"</font>);
247 }
248 </pre></blockquote>
249 The above is the same as (for example):
250 <blockquote><pre>
251 error.<font color=blue>render</font>(out, "some_field_name", <font color=blue>"inside"</font>, <font color=blue>"outside"</font>);
252 </pre></blockquote>
253 Note: The object representing the error for the field is written as
254 is. Typically for strings, this works fine. However, for more complex
255 objects (like say a list holding more than 1 error for the same field),
256 the list is printed as-is. For more formatting options for complex
257 objects, obtain and print the error manually.
258
259 @param inside this string is written before the span tag is closed
260 @param outside this string is written right after the span tag is closed.
261 */
262 public void render(
263 Writer out, String fieldName, String inside, String outside)
264 throws IOException
265 {
266 if (fieldErrors == null) {
267 return;
268 }
269
270 Object obj = fieldErrors.get(fieldName);
271 if (obj == null)
272 return;
273
274 out.write("<span class='field-errmsg'>");
275 out.write(String.valueOf(obj));
276 out.write(inside);
277 out.write("</span>");
278 out.write(outside);
279 }
280
281
282
283 public static void main (String args[]) throws Exception
284 {
285 Errors e = new Errors();
286 e.addFieldError("a", "some field error");
287 List list = new ArrayList();
288 list.add("item1");
289 list.add("item2");
290 e.addFieldError("b", list);
291 System.out.println("Has warnings: [should be false]: " + e.hasWarning());
292 System.out.println("Has errors: [should be true]: " + e.hasError());
293 e.addFormError("some form error");
294 System.out.println("Has errors: [should be true]: " + e.hasError());
295 PrintWriter pw = new PrintWriter(System.out);
296 pw.println("\n--------- form errors ---------");
297 e.renderFormErrors(pw);
298 pw.println("\n--------- field errors [a]--------");
299 e.render(pw, "a");
300 pw.println("\n--------- field errors [b]--------");
301 e.render(pw, "b");
302 pw.println("\n--------- field errors [c/non-existent]--------");
303 e.render(pw, "c");
304 pw.flush();
305 }
306
307 }