|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
BaseValidator.java | 66.7% | 53.1% | 64.7% | 58.2% |
|
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.util.ClasspathResource; | |
26 | import org.apache.hivemind.util.PropertyUtils; | |
27 | import org.apache.tapestry.IEngine; | |
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 | private boolean _clientScriptingEnabled = false; | |
96 | ||
97 | /** | |
98 | * Standard constructor. Leaves locale as system default and required as false. | |
99 | */ | |
100 | ||
101 | 71 | public BaseValidator() |
102 | { | |
103 | } | |
104 | ||
105 | /** | |
106 | * Allow the validator to be initialized with a property initialization string. | |
107 | * | |
108 | * @since 4.0 | |
109 | */ | |
110 | 7 | public BaseValidator(String initializer) |
111 | { | |
112 | 7 | PropertyUtils.configureProperties(this, initializer); |
113 | } | |
114 | ||
115 | 0 | protected BaseValidator(boolean required) |
116 | { | |
117 | 0 | _required = required; |
118 | } | |
119 | ||
120 | 5 | public boolean isRequired() |
121 | { | |
122 | 5 | return _required; |
123 | } | |
124 | ||
125 | 4 | public void setRequired(boolean required) |
126 | { | |
127 | 4 | _required = required; |
128 | } | |
129 | ||
130 | /** | |
131 | * Gets a pattern, either as the default value, or as a localized key. If override is null, then | |
132 | * the key from the <code>org.apache.tapestry.valid.ValidationStrings</code> | |
133 | * {@link ResourceBundle}(in the specified locale) is used. The pattern can then be used with | |
134 | * {@link #formatString(String, Object[])}. | |
135 | * <p> | |
136 | * Why do we not just lump these strings into TapestryStrings.properties? because | |
137 | * TapestryStrings.properties is localized to the server's locale, which is fine for the | |
138 | * logging, debugging and error messages it contains. For field validation, whose errors are | |
139 | * visible to the end user normally, we want to localize to the page's locale. | |
140 | * | |
141 | * @param override | |
142 | * The override value for the localized string from the bundle. | |
143 | * @param key | |
144 | * used to lookup pattern from bundle, if override is null. | |
145 | * @param locale | |
146 | * used to get right localization of bundle. | |
147 | * @since 3.0 | |
148 | */ | |
149 | ||
150 | 36 | protected String getPattern(String override, String key, Locale locale) |
151 | { | |
152 | 36 | if (override != null) |
153 | 10 | return override; |
154 | ||
155 | 26 | ResourceBundle strings = ResourceBundle.getBundle( |
156 | "org.apache.tapestry.valid.ValidationStrings", | |
157 | locale); | |
158 | ||
159 | 26 | return strings.getString(key); |
160 | } | |
161 | ||
162 | /** | |
163 | * Gets a string from the standard resource bundle. The string in the bundle is treated as a | |
164 | * pattern for {@link MessageFormat#format(java.lang.String, java.lang.Object[])}. | |
165 | * | |
166 | * @param pattern | |
167 | * string the input pattern to be used with | |
168 | * {@link MessageFormat#format(java.lang.String, java.lang.Object[])}. It may | |
169 | * contain replaceable parameters, {0}, {1}, etc. | |
170 | * @param args | |
171 | * the arguments used to fill replaceable parameters {0}, {1}, etc. | |
172 | * @since 3.0 | |
173 | */ | |
174 | ||
175 | 41 | protected String formatString(String pattern, Object[] args) |
176 | { | |
177 | 41 | return MessageFormat.format(pattern, args); |
178 | } | |
179 | ||
180 | /** | |
181 | * Convienience method for invoking {@link #formatString(String, Object[])}. | |
182 | * | |
183 | * @since 3.0 | |
184 | */ | |
185 | ||
186 | 16 | protected String formatString(String pattern, Object arg) |
187 | { | |
188 | 16 | return formatString(pattern, new Object[] |
189 | { arg }); | |
190 | } | |
191 | ||
192 | /** | |
193 | * Convienience method for invoking {@link #formatString(String, Object[])}. | |
194 | * | |
195 | * @since 3.0 | |
196 | */ | |
197 | ||
198 | 24 | protected String formatString(String pattern, Object arg1, Object arg2) |
199 | { | |
200 | 24 | return formatString(pattern, new Object[] |
201 | { arg1, arg2 }); | |
202 | } | |
203 | ||
204 | /** | |
205 | * Invoked to check if the value is null. If the value is null (or empty), but the required flag | |
206 | * is set, then this method throws a {@link ValidatorException}. Otherwise, returns true if the | |
207 | * value is null. | |
208 | */ | |
209 | ||
210 | 58 | protected boolean checkRequired(IFormComponent field, String value) throws ValidatorException |
211 | { | |
212 | 58 | boolean isEmpty = HiveMind.isBlank(value); |
213 | ||
214 | 58 | if (_required && isEmpty) |
215 | 2 | throw new ValidatorException(buildRequiredMessage(field), ValidationConstraint.REQUIRED); |
216 | ||
217 | 56 | return isEmpty; |
218 | } | |
219 | ||
220 | /** | |
221 | * Builds an error message indicating a value for a required field was not supplied. | |
222 | * | |
223 | * @since 3.0 | |
224 | */ | |
225 | ||
226 | 3 | protected String buildRequiredMessage(IFormComponent field) |
227 | { | |
228 | 3 | String pattern = getPattern(_requiredMessage, "field-is-required", field.getPage() |
229 | .getLocale()); | |
230 | ||
231 | 3 | return formatString(pattern, field.getDisplayName()); |
232 | } | |
233 | ||
234 | /** | |
235 | * This implementation does nothing. Subclasses may supply their own implementation. | |
236 | * | |
237 | * @since 2.2 | |
238 | */ | |
239 | ||
240 | 0 | public void renderValidatorContribution(IFormComponent field, IMarkupWriter writer, |
241 | IRequestCycle cycle) | |
242 | { | |
243 | } | |
244 | ||
245 | /** | |
246 | * Invoked (from sub-class implementations of | |
247 | * {@link #renderValidatorContribution(IFormComponent, IMarkupWriter, IRequestCycle)}to process | |
248 | * a standard validation script. This expects that: | |
249 | * <ul> | |
250 | * <li>The {@link IFormComponent}is (ultimately) wrapped by a {@link Body} | |
251 | * <li>The script generates a symbol named "function" (as per {@link #FUNCTION_SYMBOL}) | |
252 | * </ul> | |
253 | * | |
254 | * @param scriptPath | |
255 | * the resource path of the script to execute | |
256 | * @param cycle | |
257 | * The active request cycle | |
258 | * @param field | |
259 | * The field to be validated | |
260 | * @param symbols | |
261 | * a set of input symbols needed by the script. These symbols are augmented with | |
262 | * symbols for the field, form and validator. symbols may be null, but will be | |
263 | * modified if not null. | |
264 | * @throws ApplicationRuntimeException | |
265 | * if there's an error processing the script. | |
266 | * @since 2.2 | |
267 | */ | |
268 | ||
269 | 0 | protected void processValidatorScript(String scriptPath, IRequestCycle cycle, |
270 | IFormComponent field, Map symbols) | |
271 | { | |
272 | 0 | IEngine engine = field.getPage().getEngine(); |
273 | 0 | IScriptSource source = engine.getScriptSource(); |
274 | 0 | IForm form = field.getForm(); |
275 | ||
276 | 0 | Map finalSymbols = (symbols == null) ? new HashMap() : symbols; |
277 | ||
278 | 0 | finalSymbols.put(FIELD_SYMBOL, field); |
279 | 0 | finalSymbols.put(FORM_SYMBOL, form); |
280 | 0 | finalSymbols.put(VALIDATOR_SYMBOL, this); |
281 | ||
282 | 0 | Resource location = new ClasspathResource(engine.getClassResolver(), scriptPath); |
283 | ||
284 | 0 | IScript script = source.getScript(location); |
285 | ||
286 | // If there's an error, report it against the field (this validator object doesn't | |
287 | // have a location). | |
288 | ||
289 | 0 | PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, field); |
290 | ||
291 | 0 | script.execute(cycle, pageRenderSupport, finalSymbols); |
292 | } | |
293 | ||
294 | /** | |
295 | * Returns true if client scripting is enabled. Some validators are capable of generating | |
296 | * client-side scripting to perform validation when the form is submitted. By default, this flag | |
297 | * is false and subclasses should check it (in | |
298 | * {@link #renderValidatorContribution(IFormComponent, IMarkupWriter, IRequestCycle)}) before | |
299 | * generating client side script. | |
300 | * | |
301 | * @since 2.2 | |
302 | */ | |
303 | ||
304 | 0 | public boolean isClientScriptingEnabled() |
305 | { | |
306 | 0 | return _clientScriptingEnabled; |
307 | } | |
308 | ||
309 | 0 | public void setClientScriptingEnabled(boolean clientScriptingEnabled) |
310 | { | |
311 | 0 | _clientScriptingEnabled = clientScriptingEnabled; |
312 | } | |
313 | ||
314 | 0 | public String getRequiredMessage() |
315 | { | |
316 | 0 | return _requiredMessage; |
317 | } | |
318 | ||
319 | /** | |
320 | * Overrides the <code>field-is-required</code> bundle key. Parameter {0} is the display name | |
321 | * of the field. | |
322 | * | |
323 | * @since 3.0 | |
324 | */ | |
325 | ||
326 | 1 | public void setRequiredMessage(String string) |
327 | { | |
328 | 1 | _requiredMessage = string; |
329 | } | |
330 | ||
331 | } |
|