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 private int _minimumLength; 038 039 private String _minimumLengthMessage; 040 041 private String _invalidUrlFormatMessage; 042 043 private String _disallowedProtocolMessage; 044 045 private Collection _allowedProtocols; 046 047 private String _scriptPath = "/org/apache/tapestry/valid/UrlValidator.script"; //$NON-NLS-1$ 048 049 public UrlValidator() 050 { 051 } 052 053 /** 054 * Initializes the UrlValidator with properties defined by the initializer. 055 * 056 * @since 4.0 057 */ 058 059 public UrlValidator(String initializer) 060 { 061 super(initializer); 062 } 063 064 public String toString(IFormComponent field, Object value) 065 { 066 if (value == null) 067 return null; 068 069 return value.toString(); 070 } 071 072 public Object toObject(IFormComponent field, String input) throws ValidatorException 073 { 074 if (checkRequired(field, input)) 075 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)) 086 { 087 throw new ValidatorException(buildDisallowedProtocolMessage(field), 088 ValidationConstraint.DISALLOWED_PROTOCOL); 089 } 090 091 return input; 092 } 093 094 public int getMinimumLength() 095 { 096 return _minimumLength; 097 } 098 099 public void setMinimumLength(int minimumLength) 100 { 101 _minimumLength = minimumLength; 102 } 103 104 public void renderValidatorContribution(IFormComponent field, IMarkupWriter writer, 105 IRequestCycle cycle) 106 { 107 if (!isClientScriptingEnabled()) 108 return; 109 110 Map symbols = new HashMap(); 111 112 if (isRequired()) 113 symbols.put("requiredMessage", buildRequiredMessage(field)); //$NON-NLS-1$ 114 115 if (_minimumLength > 0) 116 symbols.put("minimumLengthMessage", //$NON-NLS-1$ 117 buildMinimumLengthMessage(field)); 118 119 symbols.put("urlFormatMessage", buildInvalidUrlFormatMessage(field)); //$NON-NLS-1$ 120 121 symbols.put("urlDisallowedProtocolMessage", //$NON-NLS-1$ 122 buildDisallowedProtocolMessage(field)); 123 124 symbols.put("urlRegexpProtocols", buildUrlRegexpProtocols()); //$NON-NLS-1$ 125 126 processValidatorScript(_scriptPath, cycle, field, symbols); 127 } 128 129 private String buildUrlRegexpProtocols() 130 { 131 if (_allowedProtocols == null) 132 { 133 return null; 134 } 135 String regexp = "/("; //$NON-NLS-1$ 136 Iterator iter = _allowedProtocols.iterator(); 137 while (iter.hasNext()) 138 { 139 String protocol = (String) iter.next(); 140 regexp += protocol; 141 if (iter.hasNext()) 142 { 143 regexp += "|"; //$NON-NLS-1$ 144 } 145 } 146 regexp += "):///"; //$NON-NLS-1$ 147 return regexp; 148 } 149 150 public String getScriptPath() 151 { 152 return _scriptPath; 153 } 154 155 public void setScriptPath(String scriptPath) 156 { 157 _scriptPath = scriptPath; 158 } 159 160 protected boolean isValidUrl(String url) 161 { 162 boolean bIsValid; 163 try 164 { 165 new URL(url); 166 bIsValid = true; 167 } 168 catch (MalformedURLException mue) 169 { 170 bIsValid = false; 171 } 172 return bIsValid; 173 } 174 175 protected boolean isAllowedProtocol(String url) 176 { 177 boolean bIsAllowed = false; 178 if (_allowedProtocols != null) 179 { 180 URL oUrl; 181 try 182 { 183 oUrl = new URL(url); 184 } 185 catch (MalformedURLException e) 186 { 187 return false; 188 } 189 String actualProtocol = oUrl.getProtocol(); 190 Iterator iter = _allowedProtocols.iterator(); 191 while (iter.hasNext()) 192 { 193 String protocol = (String) iter.next(); 194 if (protocol.equals(actualProtocol)) 195 { 196 bIsAllowed = true; 197 break; 198 } 199 } 200 } 201 else 202 { 203 bIsAllowed = true; 204 } 205 return bIsAllowed; 206 } 207 208 public String getInvalidUrlFormatMessage() 209 { 210 return _invalidUrlFormatMessage; 211 } 212 213 public String getMinimumLengthMessage() 214 { 215 return _minimumLengthMessage; 216 } 217 218 public void setInvalidUrlFormatMessage(String string) 219 { 220 _invalidUrlFormatMessage = string; 221 } 222 223 public String getDisallowedProtocolMessage() 224 { 225 return _disallowedProtocolMessage; 226 } 227 228 public void setDisallowedProtocolMessage(String string) 229 { 230 _disallowedProtocolMessage = string; 231 } 232 233 public void setMinimumLengthMessage(String string) 234 { 235 _minimumLengthMessage = string; 236 } 237 238 protected String buildMinimumLengthMessage(IFormComponent field) 239 { 240 String pattern = getPattern(_minimumLengthMessage, "field-too-short", //$NON-NLS-1$ 241 field.getPage().getLocale()); 242 243 return formatString(pattern, Integer.toString(_minimumLength), field.getDisplayName()); 244 } 245 246 protected String buildInvalidUrlFormatMessage(IFormComponent field) 247 { 248 String pattern = getPattern(_invalidUrlFormatMessage, "invalid-url-format", //$NON-NLS-1$ 249 field.getPage().getLocale()); 250 251 return formatString(pattern, field.getDisplayName()); 252 } 253 254 protected String buildDisallowedProtocolMessage(IFormComponent field) 255 { 256 if (_allowedProtocols == null) 257 { 258 return null; 259 } 260 String pattern = getPattern(_disallowedProtocolMessage, "disallowed-protocol", //$NON-NLS-1$ 261 field.getPage().getLocale()); 262 263 String allowedProtocols = ""; //$NON-NLS-1$ 264 Iterator iter = _allowedProtocols.iterator(); 265 while (iter.hasNext()) 266 { 267 String protocol = (String) iter.next(); 268 if (!allowedProtocols.equals("")) { //$NON-NLS-1$ 269 if (iter.hasNext()) 270 { 271 allowedProtocols += ", "; //$NON-NLS-1$ 272 } 273 else 274 { 275 allowedProtocols += " or "; //$NON-NLS-1$ 276 } 277 } 278 allowedProtocols += protocol; 279 } 280 281 return formatString(pattern, allowedProtocols); 282 } 283 284 protected String getPattern(String override, String key, Locale locale) 285 { 286 if (override != null) 287 return override; 288 289 ResourceBundle strings = ResourceBundle.getBundle( 290 "org.apache.tapestry.valid.ValidationStrings", 291 locale); 292 return strings.getString(key); 293 } 294 295 /** 296 * @param protocols 297 * comma separated list of allowed protocols 298 */ 299 public void setAllowedProtocols(String protocols) 300 { 301 StringSplitter spliter = new StringSplitter(','); 302 // String[] aProtocols = protocols.split(","); //$NON-NLS-1$ 303 String[] aProtocols = spliter.splitToArray(protocols); //$NON-NLS-1$ 304 _allowedProtocols = new Vector(); 305 for (int i = 0; i < aProtocols.length; i++) 306 { 307 _allowedProtocols.add(aProtocols[i]); 308 } 309 } 310 311 }