Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
BaseValidator |
|
| 1.2222222222222223;1.222 |
1 | // Copyright 2004, 2005 The Apache Software Foundation |
|
2 | // |
|
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
|
4 | // you may not use this file except in compliance with the License. |
|
5 | // You may obtain a copy of the License at |
|
6 | // |
|
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
|
8 | // |
|
9 | // Unless required by applicable law or agreed to in writing, software |
|
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
|
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
12 | // See the License for the specific language governing permissions and |
|
13 | // limitations under the License. |
|
14 | ||
15 | package org.apache.tapestry.valid; |
|
16 | ||
17 | import java.text.MessageFormat; |
|
18 | import java.util.HashMap; |
|
19 | import java.util.Locale; |
|
20 | import java.util.Map; |
|
21 | import java.util.ResourceBundle; |
|
22 | ||
23 | import org.apache.hivemind.HiveMind; |
|
24 | import org.apache.hivemind.Resource; |
|
25 | import org.apache.hivemind.impl.DefaultClassResolver; |
|
26 | import org.apache.hivemind.util.ClasspathResource; |
|
27 | import org.apache.hivemind.util.PropertyUtils; |
|
28 | import org.apache.tapestry.IForm; |
|
29 | import org.apache.tapestry.IMarkupWriter; |
|
30 | import org.apache.tapestry.IRequestCycle; |
|
31 | import org.apache.tapestry.IScript; |
|
32 | import org.apache.tapestry.PageRenderSupport; |
|
33 | import org.apache.tapestry.TapestryUtils; |
|
34 | import org.apache.tapestry.engine.IScriptSource; |
|
35 | import org.apache.tapestry.form.IFormComponent; |
|
36 | ||
37 | /** |
|
38 | * Abstract base class for {@link IValidator}. Supports a required and locale property. |
|
39 | * |
|
40 | * @author Howard Lewis Ship |
|
41 | * @since 1.0.8 |
|
42 | */ |
|
43 | ||
44 | public abstract class BaseValidator implements IValidator |
|
45 | { |
|
46 | /** |
|
47 | * Input Symbol used to represent the field being validated. |
|
48 | * |
|
49 | * @see #processValidatorScript(String, IRequestCycle, IFormComponent, Map) |
|
50 | * @since 2.2 |
|
51 | */ |
|
52 | ||
53 | public static final String FIELD_SYMBOL = "field"; |
|
54 | ||
55 | /** |
|
56 | * Input symbol used to represent the validator itself to the script. |
|
57 | * |
|
58 | * @see #processValidatorScript(String, IRequestCycle, IFormComponent, Map) |
|
59 | * @since 2.2 |
|
60 | */ |
|
61 | ||
62 | public static final String VALIDATOR_SYMBOL = "validator"; |
|
63 | ||
64 | /** |
|
65 | * Input symbol used to represent the {@link IForm}containing the field to the script. |
|
66 | * |
|
67 | * @see #processValidatorScript(String, IRequestCycle, IFormComponent, Map) |
|
68 | * @since 2.2 |
|
69 | */ |
|
70 | ||
71 | public static final String FORM_SYMBOL = "form"; |
|
72 | ||
73 | /** |
|
74 | * Output symbol set by the script asthe name of the validator JavaScript function. The function |
|
75 | * implemented must return true or false (true if the field is valid, false otherwise). After |
|
76 | * the script is executed, the function is added to the {@link IForm}as a |
|
77 | * {@link org.apache.tapestry.form.FormEventType#SUBMIT}. |
|
78 | * |
|
79 | * @see #processValidatorScript(String, IRequestCycle, IFormComponent, Map) |
|
80 | * @since 2.2 |
|
81 | */ |
|
82 | ||
83 | public static final String FUNCTION_SYMBOL = "function"; |
|
84 | ||
85 | private boolean _required; |
|
86 | ||
87 | /** @since 3.0 */ |
|
88 | ||
89 | private String _requiredMessage; |
|
90 | ||
91 | /** |
|
92 | * @since 2.2 |
|
93 | */ |
|
94 | ||
95 | 20 | private boolean _clientScriptingEnabled = false; |
96 | ||
97 | /** |
|
98 | * @since 4.1 |
|
99 | */ |
|
100 | private IScriptSource _scriptSource; |
|
101 | ||
102 | /** |
|
103 | * Standard constructor. Leaves locale as system default and required as false. |
|
104 | */ |
|
105 | ||
106 | public BaseValidator() |
|
107 | 13 | { |
108 | 13 | } |
109 | ||
110 | /** |
|
111 | * Allow the validator to be initialized with a property initialization string. |
|
112 | * |
|
113 | * @since 4.0 |
|
114 | */ |
|
115 | public BaseValidator(String initializer) |
|
116 | 7 | { |
117 | 7 | PropertyUtils.configureProperties(this, initializer); |
118 | 7 | } |
119 | ||
120 | protected BaseValidator(boolean required) |
|
121 | 0 | { |
122 | 0 | _required = required; |
123 | 0 | } |
124 | ||
125 | public boolean isRequired() |
|
126 | { |
|
127 | 5 | return _required; |
128 | } |
|
129 | ||
130 | public void setRequired(boolean required) |
|
131 | { |
|
132 | 68 | _required = required; |
133 | 68 | } |
134 | ||
135 | public void setScriptSource(IScriptSource scriptSource) |
|
136 | { |
|
137 | 0 | _scriptSource = scriptSource; |
138 | 0 | } |
139 | ||
140 | /** |
|
141 | * Gets a pattern, either as the default value, or as a localized key. If override is null, then |
|
142 | * the key from the <code>org.apache.tapestry.valid.ValidationStrings</code> |
|
143 | * {@link ResourceBundle}(in the specified locale) is used. The pattern can then be used with |
|
144 | * {@link #formatString(String, Object[])}. |
|
145 | * <p> |
|
146 | * Why do we not just lump these strings into TapestryStrings.properties? because |
|
147 | * TapestryStrings.properties is localized to the server's locale, which is fine for the |
|
148 | * logging, debugging and error messages it contains. For field validation, whose errors are |
|
149 | * visible to the end user normally, we want to localize to the page's locale. |
|
150 | * |
|
151 | * @param override |
|
152 | * The override value for the localized string from the bundle. |
|
153 | * @param key |
|
154 | * used to lookup pattern from bundle, if override is null. |
|
155 | * @param locale |
|
156 | * used to get right localization of bundle. |
|
157 | * @since 3.0 |
|
158 | */ |
|
159 | ||
160 | protected String getPattern(String override, String key, Locale locale) |
|
161 | { |
|
162 | 36 | if (override != null) |
163 | 10 | return override; |
164 | ||
165 | 26 | ResourceBundle strings = ResourceBundle.getBundle( |
166 | "org.apache.tapestry.valid.ValidationStrings", |
|
167 | locale); |
|
168 | ||
169 | 26 | return strings.getString(key); |
170 | } |
|
171 | ||
172 | /** |
|
173 | * Gets a string from the standard resource bundle. The string in the bundle is treated as a |
|
174 | * pattern for {@link MessageFormat#format(java.lang.String, java.lang.Object[])}. |
|
175 | * |
|
176 | * @param pattern |
|
177 | * string the input pattern to be used with |
|
178 | * {@link MessageFormat#format(java.lang.String, java.lang.Object[])}. It may |
|
179 | * contain replaceable parameters, {0}, {1}, etc. |
|
180 | * @param args |
|
181 | * the arguments used to fill replaceable parameters {0}, {1}, etc. |
|
182 | * @since 3.0 |
|
183 | */ |
|
184 | ||
185 | protected String formatString(String pattern, Object[] args) |
|
186 | { |
|
187 | 41 | return MessageFormat.format(pattern, args); |
188 | } |
|
189 | ||
190 | /** |
|
191 | * Convienience method for invoking {@link #formatString(String, Object[])}. |
|
192 | * |
|
193 | * @since 3.0 |
|
194 | */ |
|
195 | ||
196 | protected String formatString(String pattern, Object arg) |
|
197 | { |
|
198 | 16 | return formatString(pattern, new Object[] |
199 | { arg }); |
|
200 | } |
|
201 | ||
202 | /** |
|
203 | * Convienience method for invoking {@link #formatString(String, Object[])}. |
|
204 | * |
|
205 | * @since 3.0 |
|
206 | */ |
|
207 | ||
208 | protected String formatString(String pattern, Object arg1, Object arg2) |
|
209 | { |
|
210 | 24 | return formatString(pattern, new Object[] |
211 | { arg1, arg2 }); |
|
212 | } |
|
213 | ||
214 | /** |
|
215 | * Invoked to check if the value is null. If the value is null (or empty), but the required flag |
|
216 | * is set, then this method throws a {@link ValidatorException}. Otherwise, returns true if the |
|
217 | * value is null. |
|
218 | */ |
|
219 | ||
220 | protected boolean checkRequired(IFormComponent field, String value) throws ValidatorException |
|
221 | { |
|
222 | 58 | boolean isEmpty = HiveMind.isBlank(value); |
223 | ||
224 | 58 | if (_required && isEmpty) |
225 | 2 | throw new ValidatorException(buildRequiredMessage(field), ValidationConstraint.REQUIRED); |
226 | ||
227 | 56 | return isEmpty; |
228 | } |
|
229 | ||
230 | /** |
|
231 | * Builds an error message indicating a value for a required field was not supplied. |
|
232 | * |
|
233 | * @since 3.0 |
|
234 | */ |
|
235 | ||
236 | protected String buildRequiredMessage(IFormComponent field) |
|
237 | { |
|
238 | 3 | String pattern = getPattern(_requiredMessage, "field-is-required", field.getPage() |
239 | .getLocale()); |
|
240 | ||
241 | 3 | return formatString(pattern, field.getDisplayName()); |
242 | } |
|
243 | ||
244 | /** |
|
245 | * This implementation does nothing. Subclasses may supply their own implementation. |
|
246 | * |
|
247 | * @since 2.2 |
|
248 | */ |
|
249 | ||
250 | public void renderValidatorContribution(IFormComponent field, IMarkupWriter writer, |
|
251 | IRequestCycle cycle) |
|
252 | { |
|
253 | 0 | } |
254 | ||
255 | /** |
|
256 | * Invoked (from sub-class implementations of |
|
257 | * {@link #renderValidatorContribution(IFormComponent, IMarkupWriter, IRequestCycle)}to process |
|
258 | * a standard validation script. This expects that: |
|
259 | * <ul> |
|
260 | * <li>The {@link IFormComponent}is (ultimately) wrapped by a {@link Body} |
|
261 | * <li>The script generates a symbol named "function" (as per {@link #FUNCTION_SYMBOL}) |
|
262 | * </ul> |
|
263 | * |
|
264 | * @param scriptPath |
|
265 | * the resource path of the script to execute |
|
266 | * @param cycle |
|
267 | * The active request cycle |
|
268 | * @param field |
|
269 | * The field to be validated |
|
270 | * @param symbols |
|
271 | * a set of input symbols needed by the script. These symbols are augmented with |
|
272 | * symbols for the field, form and validator. symbols may be null, but will be |
|
273 | * modified if not null. |
|
274 | * @throws ApplicationRuntimeException |
|
275 | * if there's an error processing the script. |
|
276 | * @since 2.2 |
|
277 | */ |
|
278 | ||
279 | protected void processValidatorScript(String scriptPath, IRequestCycle cycle, |
|
280 | IFormComponent field, Map symbols) |
|
281 | { |
|
282 | 0 | IForm form = field.getForm(); |
283 | ||
284 | 0 | Map finalSymbols = (symbols == null) ? new HashMap() : symbols; |
285 | ||
286 | 0 | finalSymbols.put(FIELD_SYMBOL, field); |
287 | 0 | finalSymbols.put(FORM_SYMBOL, form); |
288 | 0 | finalSymbols.put(VALIDATOR_SYMBOL, this); |
289 | ||
290 | 0 | Resource location = new ClasspathResource(new DefaultClassResolver(), scriptPath); |
291 | ||
292 | 0 | IScript script = _scriptSource.getScript(location); |
293 | ||
294 | // If there's an error, report it against the field (this validator object doesn't |
|
295 | // have a location). |
|
296 | ||
297 | 0 | PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, field); |
298 | ||
299 | 0 | script.execute(field, cycle, pageRenderSupport, finalSymbols); |
300 | 0 | } |
301 | ||
302 | /** |
|
303 | * Returns true if client scripting is enabled. Some validators are capable of generating |
|
304 | * client-side scripting to perform validation when the form is submitted. By default, this flag |
|
305 | * is false and subclasses should check it (in |
|
306 | * {@link #renderValidatorContribution(IFormComponent, IMarkupWriter, IRequestCycle)}) before |
|
307 | * generating client side script. |
|
308 | * |
|
309 | * @since 2.2 |
|
310 | */ |
|
311 | ||
312 | public boolean isClientScriptingEnabled() |
|
313 | { |
|
314 | 0 | return _clientScriptingEnabled; |
315 | } |
|
316 | ||
317 | public void setClientScriptingEnabled(boolean clientScriptingEnabled) |
|
318 | { |
|
319 | 17 | _clientScriptingEnabled = clientScriptingEnabled; |
320 | 17 | } |
321 | ||
322 | public String getRequiredMessage() |
|
323 | { |
|
324 | 0 | return _requiredMessage; |
325 | } |
|
326 | ||
327 | /** |
|
328 | * Overrides the <code>field-is-required</code> bundle key. Parameter {0} is the display name |
|
329 | * of the field. |
|
330 | * |
|
331 | * @since 3.0 |
|
332 | */ |
|
333 | ||
334 | public void setRequiredMessage(String string) |
|
335 | { |
|
336 | 65 | _requiredMessage = string; |
337 | 65 | } |
338 | ||
339 | } |