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 }