001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.valid;
016
017 import java.net.MalformedURLException;
018 import java.net.URL;
019 import java.util.Collection;
020 import java.util.HashMap;
021 import java.util.Iterator;
022 import java.util.Locale;
023 import java.util.Map;
024 import java.util.ResourceBundle;
025 import java.util.Vector;
026
027 import org.apache.tapestry.IMarkupWriter;
028 import org.apache.tapestry.IRequestCycle;
029 import org.apache.tapestry.form.IFormComponent;
030 import org.apache.tapestry.util.StringSplitter;
031
032 /**
033 * @since 3.0
034 */
035 public class UrlValidator extends BaseValidator
036 {
037
038 private int _minimumLength;
039
040 private String _minimumLengthMessage;
041
042 private String _invalidUrlFormatMessage;
043
044 private String _disallowedProtocolMessage;
045
046 private Collection _allowedProtocols;
047
048 private String _scriptPath = "/org/apache/tapestry/valid/UrlValidator.script"; //$NON-NLS-1$
049
050 public UrlValidator()
051 {
052 }
053
054 /**
055 * Initializes the UrlValidator with properties defined by the initializer.
056 *
057 * @since 4.0
058 */
059
060 public UrlValidator(String initializer)
061 {
062 super(initializer);
063 }
064
065 public String toString(IFormComponent field, Object value)
066 {
067 if (value == null) return null;
068
069 return value.toString();
070 }
071
072 public Object toObject(IFormComponent field, String input)
073 throws ValidatorException
074 {
075 if (checkRequired(field, input)) return null;
076
077 if (_minimumLength > 0 && input.length() < _minimumLength)
078 throw new ValidatorException(buildMinimumLengthMessage(field),
079 ValidationConstraint.MINIMUM_WIDTH);
080
081 if (!isValidUrl(input))
082 throw new ValidatorException(buildInvalidUrlFormatMessage(field),
083 ValidationConstraint.URL_FORMAT);
084
085 if (!isAllowedProtocol(input)) { throw new ValidatorException(
086 buildDisallowedProtocolMessage(field),
087 ValidationConstraint.DISALLOWED_PROTOCOL); }
088
089 return input;
090 }
091
092 public int getMinimumLength()
093 {
094 return _minimumLength;
095 }
096
097 public void setMinimumLength(int minimumLength)
098 {
099 _minimumLength = minimumLength;
100 }
101
102 public void renderValidatorContribution(IFormComponent field,
103 IMarkupWriter writer, IRequestCycle cycle)
104 {
105 if (!isClientScriptingEnabled()) return;
106
107 Map symbols = new HashMap();
108
109 if (isRequired())
110 symbols.put("requiredMessage", buildRequiredMessage(field)); //$NON-NLS-1$
111
112 if (_minimumLength > 0) symbols.put("minimumLengthMessage", //$NON-NLS-1$
113 buildMinimumLengthMessage(field));
114
115 symbols.put("urlFormatMessage", buildInvalidUrlFormatMessage(field)); //$NON-NLS-1$
116
117 symbols.put("urlDisallowedProtocolMessage", //$NON-NLS-1$
118 buildDisallowedProtocolMessage(field));
119
120 symbols.put("urlRegexpProtocols", buildUrlRegexpProtocols()); //$NON-NLS-1$
121
122 processValidatorScript(_scriptPath, cycle, field, symbols);
123 }
124
125 private String buildUrlRegexpProtocols()
126 {
127 if (_allowedProtocols == null) { return null; }
128 String regexp = "/("; //$NON-NLS-1$
129 Iterator iter = _allowedProtocols.iterator();
130 while(iter.hasNext())
131 {
132 String protocol = (String) iter.next();
133 regexp += protocol;
134 if (iter.hasNext())
135 {
136 regexp += "|"; //$NON-NLS-1$
137 }
138 }
139 regexp += "):///"; //$NON-NLS-1$
140 return regexp;
141 }
142
143 public String getScriptPath()
144 {
145 return _scriptPath;
146 }
147
148 public void setScriptPath(String scriptPath)
149 {
150 _scriptPath = scriptPath;
151 }
152
153 protected boolean isValidUrl(String url)
154 {
155 boolean bIsValid;
156 try
157 {
158 new URL(url);
159 bIsValid = true;
160 }
161 catch (MalformedURLException mue)
162 {
163 bIsValid = false;
164 }
165 return bIsValid;
166 }
167
168 protected boolean isAllowedProtocol(String url)
169 {
170 boolean bIsAllowed = false;
171 if (_allowedProtocols != null)
172 {
173 URL oUrl;
174 try
175 {
176 oUrl = new URL(url);
177 }
178 catch (MalformedURLException e)
179 {
180 return false;
181 }
182 String actualProtocol = oUrl.getProtocol();
183 Iterator iter = _allowedProtocols.iterator();
184 while(iter.hasNext())
185 {
186 String protocol = (String) iter.next();
187 if (protocol.equals(actualProtocol))
188 {
189 bIsAllowed = true;
190 break;
191 }
192 }
193 }
194 else
195 {
196 bIsAllowed = true;
197 }
198 return bIsAllowed;
199 }
200
201 public String getInvalidUrlFormatMessage()
202 {
203 return _invalidUrlFormatMessage;
204 }
205
206 public String getMinimumLengthMessage()
207 {
208 return _minimumLengthMessage;
209 }
210
211 public void setInvalidUrlFormatMessage(String string)
212 {
213 _invalidUrlFormatMessage = string;
214 }
215
216 public String getDisallowedProtocolMessage()
217 {
218 return _disallowedProtocolMessage;
219 }
220
221 public void setDisallowedProtocolMessage(String string)
222 {
223 _disallowedProtocolMessage = string;
224 }
225
226 public void setMinimumLengthMessage(String string)
227 {
228 _minimumLengthMessage = string;
229 }
230
231 protected String buildMinimumLengthMessage(IFormComponent field)
232 {
233 String pattern = getPattern(_minimumLengthMessage, "field-too-short", //$NON-NLS-1$
234 field.getPage().getLocale());
235
236 return formatString(pattern, Integer.toString(_minimumLength), field
237 .getDisplayName());
238 }
239
240 protected String buildInvalidUrlFormatMessage(IFormComponent field)
241 {
242 String pattern = getPattern(_invalidUrlFormatMessage,
243 "invalid-url-format", //$NON-NLS-1$
244 field.getPage().getLocale());
245
246 return formatString(pattern, field.getDisplayName());
247 }
248
249 protected String buildDisallowedProtocolMessage(IFormComponent field)
250 {
251 if (_allowedProtocols == null) { return null; }
252 String pattern = getPattern(_disallowedProtocolMessage,
253 "disallowed-protocol", //$NON-NLS-1$
254 field.getPage().getLocale());
255
256 String allowedProtocols = ""; //$NON-NLS-1$
257 Iterator iter = _allowedProtocols.iterator();
258 while(iter.hasNext())
259 {
260 String protocol = (String) iter.next();
261 if (!allowedProtocols.equals("")) { //$NON-NLS-1$
262 if (iter.hasNext())
263 {
264 allowedProtocols += ", "; //$NON-NLS-1$
265 }
266 else
267 {
268 allowedProtocols += " or "; //$NON-NLS-1$
269 }
270 }
271 allowedProtocols += protocol;
272 }
273
274 return formatString(pattern, allowedProtocols);
275 }
276
277 protected String getPattern(String override, String key, Locale locale)
278 {
279 if (override != null) return override;
280
281 ResourceBundle strings = ResourceBundle.getBundle(
282 "org.apache.tapestry.valid.ValidationStrings", locale);
283 return strings.getString(key);
284 }
285
286 /**
287 * @param protocols
288 * comma separated list of allowed protocols
289 */
290 public void setAllowedProtocols(String protocols)
291 {
292 StringSplitter spliter = new StringSplitter(',');
293 // String[] aProtocols = protocols.split(","); //$NON-NLS-1$
294 String[] aProtocols = spliter.splitToArray(protocols); //$NON-NLS-1$
295 _allowedProtocols = new Vector();
296 for(int i = 0; i < aProtocols.length; i++)
297 {
298 _allowedProtocols.add(aProtocols[i]);
299 }
300 }
301
302 }