Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
RegexValidator |
|
| 2.5;2.5 |
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | package javax.faces.validator; | |
20 | ||
21 | import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty; | |
22 | import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty; | |
23 | import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator; | |
24 | ||
25 | import javax.faces.component.PartialStateHolder; | |
26 | import javax.faces.component.UIComponent; | |
27 | import javax.faces.context.FacesContext; | |
28 | import java.util.regex.Pattern; | |
29 | import java.util.regex.PatternSyntaxException; | |
30 | ||
31 | /** | |
32 | * <p> | |
33 | * <strong>RegexValidator</strong> is a {@link javax.faces.validator.Validator} | |
34 | * that checks the value of the corresponding component against specified | |
35 | * pattern using Java regular expression syntax. | |
36 | * | |
37 | * The regular expression syntax accepted by the RegexValidator class is | |
38 | * same as mentioned in class {@link java.util.regex.Pattern} in package | |
39 | * <code>java.util.regex</code>. | |
40 | * </p> | |
41 | * | |
42 | * <p> | |
43 | * The following algorithm is implemented: | |
44 | * </p> | |
45 | * | |
46 | * <ul> | |
47 | * <li>If the passed value is <code>null</code>, exit immediately.</li> | |
48 | * <li> | |
49 | * If the passed value is not a String, exit with a {@link #NOT_MATCHED_MESSAGE_ID} | |
50 | * error message. | |
51 | * </li> | |
52 | * <li> | |
53 | * If no pattern has been set, or pattern resolves to <code>null</code> or an | |
54 | * empty String, throw a {@link javax.faces.validator.ValidatorException} | |
55 | * with a {@link #PATTERN_NOT_SET_MESSAGE_ID} message. | |
56 | * </li> | |
57 | * <li> | |
58 | * If pattern is not a valid regular expression, according to the rules as defined | |
59 | * in class {@link java.util.regex.Pattern}, throw a {@link ValidatorException} | |
60 | * with a (@link #MATCH_EXCEPTION_MESSAGE_ID} message. | |
61 | * </li> | |
62 | * <li> | |
63 | * If a <code>pattern</code> property has been configured on this | |
64 | * {@link javax.faces.validator.Validator}, check the passed value against this pattern. | |
65 | * If value does not match pattern throw a {@link ValidatorException} | |
66 | * containing a {@link #NOT_MATCHED_MESSAGE_ID} message. | |
67 | * </li> | |
68 | * </ul> | |
69 | * | |
70 | * @since 2.0 | |
71 | */ | |
72 | @JSFValidator( | |
73 | name="f:validateRegex", | |
74 | bodyContent="empty", | |
75 | tagClass="org.apache.myfaces.taglib.core.ValidateRegexTag") | |
76 | @JSFJspProperty( | |
77 | name="binding", | |
78 | returnType = "javax.faces.validator.RegexValidator", | |
79 | longDesc = "A ValueExpression that evaluates to a RegexValidator.") | |
80 | 0 | public class RegexValidator implements Validator, PartialStateHolder |
81 | { | |
82 | ||
83 | /** | |
84 | * Converter ID, as defined by the JSF 2.0 specification. | |
85 | */ | |
86 | public static final String VALIDATOR_ID = "javax.faces.RegularExpression"; | |
87 | ||
88 | /** | |
89 | * This message ID is used when the pattern is <code>null</code>, or an empty String. | |
90 | */ | |
91 | public static final String PATTERN_NOT_SET_MESSAGE_ID = "javax.faces.validator.RegexValidator.PATTERN_NOT_SET"; | |
92 | ||
93 | /** | |
94 | * This message ID is used when the passed value is not a String, or when | |
95 | * the pattern does not match the passed value. | |
96 | */ | |
97 | public static final String NOT_MATCHED_MESSAGE_ID = "javax.faces.validator.RegexValidator.NOT_MATCHED"; | |
98 | ||
99 | /** | |
100 | * This message ID is used when the pattern is not a valid regular expression, according | |
101 | * to the rules as defined in class {@link java.util.regex.Pattern} | |
102 | */ | |
103 | public static final String MATCH_EXCEPTION_MESSAGE_ID = "javax.faces.validator.RegexValidator.MATCH_EXCEPTION"; | |
104 | ||
105 | //TODO: Find a better place for such a common constant | |
106 | private static final String EMPTY_STRING = ""; | |
107 | ||
108 | private String pattern; | |
109 | ||
110 | 0 | private boolean isTransient = false; |
111 | ||
112 | // VALIDATE | |
113 | /** {@inheritDoc} */ | |
114 | public void validate(FacesContext context, | |
115 | UIComponent component, | |
116 | Object value) | |
117 | { | |
118 | 0 | if (context == null) |
119 | { | |
120 | 0 | throw new NullPointerException("context"); |
121 | } | |
122 | 0 | if (component == null) |
123 | { | |
124 | 0 | throw new NullPointerException("component"); |
125 | } | |
126 | ||
127 | 0 | if (value == null) |
128 | { | |
129 | 0 | return; |
130 | } | |
131 | 0 | if (!(value instanceof String)) |
132 | { | |
133 | 0 | throw new ValidatorException(_MessageUtils.getErrorMessage(context, NOT_MATCHED_MESSAGE_ID, null)); |
134 | } | |
135 | ||
136 | 0 | String string = (String) value; |
137 | ||
138 | Pattern thePattern; | |
139 | 0 | if (pattern == null |
140 | || pattern.equals(EMPTY_STRING)) | |
141 | { | |
142 | 0 | throw new ValidatorException(_MessageUtils.getErrorMessage(context, PATTERN_NOT_SET_MESSAGE_ID, null)); |
143 | } | |
144 | ||
145 | try | |
146 | { | |
147 | 0 | thePattern = Pattern.compile(pattern); |
148 | } | |
149 | 0 | catch (PatternSyntaxException pse) |
150 | { | |
151 | 0 | throw new ValidatorException(_MessageUtils.getErrorMessage(context, MATCH_EXCEPTION_MESSAGE_ID, null)); |
152 | 0 | } |
153 | ||
154 | 0 | if (!thePattern.matcher(string).matches()) |
155 | { | |
156 | //TODO: Present the patternExpression in a more user friendly way | |
157 | 0 | Object[] args = {thePattern, _MessageUtils.getLabel(context, component)}; |
158 | 0 | throw new ValidatorException(_MessageUtils.getErrorMessage(context, NOT_MATCHED_MESSAGE_ID, args)); |
159 | } | |
160 | 0 | } |
161 | ||
162 | // RESTORE & SAVE STATE | |
163 | ||
164 | /** {@inheritDoc} */ | |
165 | public Object saveState(FacesContext context) | |
166 | { | |
167 | 0 | if (!initialStateMarked()) |
168 | { | |
169 | 0 | return pattern; |
170 | } | |
171 | 0 | return null; |
172 | } | |
173 | ||
174 | /** {@inheritDoc} */ | |
175 | public void restoreState(FacesContext context, Object state) | |
176 | { | |
177 | 0 | if (state != null) |
178 | { | |
179 | //Since pattern is required, if state is null | |
180 | //nothing has changed | |
181 | 0 | this.pattern = (String) state; |
182 | } | |
183 | 0 | } |
184 | ||
185 | // SETTER & GETTER | |
186 | ||
187 | /** {@inheritDoc} */ | |
188 | public boolean isTransient() | |
189 | { | |
190 | 0 | return isTransient; |
191 | } | |
192 | ||
193 | /** {@inheritDoc} */ | |
194 | public void setTransient(boolean isTransient) | |
195 | { | |
196 | 0 | this.isTransient = isTransient; |
197 | 0 | } |
198 | ||
199 | /** | |
200 | * The Regular Expression property to validate against. This property must be a ValueExpression | |
201 | * that resolves to a String in the format of the java.util.regex patterns. | |
202 | * | |
203 | * @param pattern a ValueExpression that evaluates to a String that is the regular expression pattern | |
204 | */ | |
205 | public void setPattern(String pattern) | |
206 | { | |
207 | //TODO: Validate input parameter | |
208 | 0 | this.pattern = pattern; |
209 | 0 | clearInitialState(); |
210 | 0 | } |
211 | ||
212 | /** | |
213 | * Return the ValueExpression that yields the regular expression pattern when evaluated. | |
214 | * | |
215 | * @return The pattern. | |
216 | */ | |
217 | @JSFProperty(required = true) | |
218 | public String getPattern() | |
219 | { | |
220 | 0 | return this.pattern; |
221 | } | |
222 | ||
223 | 0 | private boolean _initialStateMarked = false; |
224 | ||
225 | public void clearInitialState() | |
226 | { | |
227 | 0 | _initialStateMarked = false; |
228 | 0 | } |
229 | ||
230 | public boolean initialStateMarked() | |
231 | { | |
232 | 0 | return _initialStateMarked; |
233 | } | |
234 | ||
235 | public void markInitialState() | |
236 | { | |
237 | 0 | _initialStateMarked = true; |
238 | 0 | } |
239 | ||
240 | @JSFProperty(faceletsOnly=true) | |
241 | @SuppressWarnings("unused") | |
242 | private Boolean isDisabled() | |
243 | { | |
244 | 0 | return null; |
245 | } | |
246 | ||
247 | @JSFProperty(faceletsOnly=true) | |
248 | @SuppressWarnings("unused") | |
249 | private String getFor() | |
250 | { | |
251 | 0 | return null; |
252 | } | |
253 | } |