Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BaseValidator |
|
| 1.3333333333333333;1.333 |
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 | 0 | 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 | 0 | { |
108 | 0 | } |
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 | 0 | { |
117 | 0 | PropertyUtils.configureProperties(this, initializer); |
118 | 0 | } |
119 | ||
120 | protected BaseValidator(boolean required) | |
121 | 0 | { |
122 | 0 | _required = required; |
123 | 0 | } |
124 | ||
125 | public boolean isRequired() | |
126 | { | |
127 | 0 | return _required; |
128 | } | |
129 | ||
130 | public void setRequired(boolean required) | |
131 | { | |
132 | 0 | _required = required; |
133 | 0 | } |
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 | 0 | if (override != null) |
163 | 0 | return override; |
164 | ||
165 | 0 | ResourceBundle strings = ResourceBundle.getBundle( |
166 | "org.apache.tapestry.valid.ValidationStrings", | |
167 | locale); | |
168 | ||
169 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | 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 | 0 | boolean isEmpty = HiveMind.isBlank(value); |
223 | ||
224 | 0 | if (_required && isEmpty) |
225 | 0 | throw new ValidatorException(buildRequiredMessage(field), ValidationConstraint.REQUIRED); |
226 | ||
227 | 0 | 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 | 0 | String pattern = getPattern(_requiredMessage, "field-is-required", field.getPage() |
239 | .getLocale()); | |
240 | ||
241 | 0 | 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 | 0 | _clientScriptingEnabled = clientScriptingEnabled; |
320 | 0 | } |
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 | 0 | _requiredMessage = string; |
337 | 0 | } |
338 | ||
339 | } |