Index: /trunk/CONTRIBUTION
===================================================================
--- /trunk/CONTRIBUTION (revision 7488)
+++ /trunk/CONTRIBUTION (revision 7489)
@@ -42,4 +42,7 @@
is from Matthias Käppler and licensed with the Apache License 2.0.
+The mail/url validator routines use code from Apache Commons
+Validator which is licensed with Apache license version 2.0.
+
The NTv2 transformation code (http://jgridshift.sourceforge.net/)
is from Peter Yuill and licensed with LGPL.
Index: /trunk/README
===================================================================
--- /trunk/README (revision 7488)
+++ /trunk/README (revision 7489)
@@ -17,5 +17,5 @@
You need JRE Version 7, or later.
-Microsoft Windows and Apple Mac OS X users should visit http://www.java.com
+Microsoft Windows and Apple Mac OS X users should visit https://www.java.com
and download the latest Java executable for their system.
@@ -144,16 +144,19 @@
src/org/apache/commons/codec (svn external)
-> http://svn.apache.org/repos/asf/commons/proper/codec/trunk/src/main/java/org/apache/commons/codec
+* Apache commons validator: Improved validator routines
+ src/org/openstreetmap/josm/data/validation/routines
+ -> http://commons.apache.org/proper/commons-validator
* SVG Salamander: Support for SVG image format
src/com/kitfox/svg
- -> http://svgsalamander.java.net/
+ -> https://svgsalamander.java.net/
* Metadata Extractor: Read EXIF Metadata of photos
src/com/drew
- -> http://www.drewnoakes.com/code/exif/
+ -> https://www.drewnoakes.com/code/exif/
* Signpost: OAuth library
src/oauth, src/com/google
- -> http://code.google.com/p/oauth-signpost/
+ -> https://code.google.com/p/oauth-signpost/
* GNU getopt Java port: Command line argument processing library
src/gnu/getopt
- -> http://www.urbanophile.com/~arenn/hacking/download.html
+ -> http://www.urbanophile.com/arenn/hacking/download.html
* MultiSplitPane: Small lib for GUI layout management
src/org/openstreetmap/josm/gui/MultiSplitLayout.java, MultiSplitPane.java
@@ -161,5 +164,3 @@
* swinghelper: Class CheckThreadViolationRepaintManager to find classpath violations
src/org/jdesktop/swinghelper/debug/CheckThreadViolationRepaintManager.java
- -> http://java.net/projects/swinghelper
-
-
+ -> https://java.net/projects/swinghelper
Index: /trunk/build.xml
===================================================================
--- /trunk/build.xml (revision 7488)
+++ /trunk/build.xml (revision 7489)
@@ -128,7 +128,4 @@
Domain name validation routines.
+ * + *+ * This validator provides methods for validating Internet domain names + * and top-level domains. + *
+ * + *Domain names are evaluated according + * to the standards RFC1034, + * section 3, and RFC1123, + * section 2.1. No accomodation is provided for the specialized needs of + * other applications; if the domain name has been URL-encoded, for example, + * validation will fail even though the equivalent plaintext version of the + * same name would have passed. + *
+ * + *+ * Validation is also provided for top-level domains (TLDs) as defined and + * maintained by the Internet Assigned Numbers Authority (IANA): + *
+ * + *.arpa
, etc.).com, .org
, etc.).us, .uk, .cn
, etc.)+ * (NOTE: This class does not provide IP address lookup for domain names or + * methods to ensure that a given domain name matches a specific IP; see + * {@link java.net.InetAddress} for that functionality.) + *
+ * + * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $ + * @since Validator 1.4 + */ +public class DomainValidator extends AbstractValidator { + + // Regular expression strings for hostnames (derived from RFC2396 and RFC 1123) + private static final String DOMAIN_LABEL_REGEX = "\\p{Alnum}(?>[\\p{Alnum}-]*\\p{Alnum})*"; + private static final String TOP_LABEL_REGEX = "\\p{Alpha}{2,}"; + private static final String DOMAIN_NAME_REGEX = + "^(?:" + DOMAIN_LABEL_REGEX + "\\.)+" + "(" + TOP_LABEL_REGEX + ")$"; + + private final boolean allowLocal; + + /** + * Singleton instance of this validator, which + * doesn't consider local addresses as valid. + */ + private static final DomainValidator DOMAIN_VALIDATOR = new DomainValidator(false); + + /** + * Singleton instance of this validator, which does + * consider local addresses valid. + */ + private static final DomainValidator DOMAIN_VALIDATOR_WITH_LOCAL = new DomainValidator(true); + + /** + * RegexValidator for matching domains. + */ + private final RegexValidator domainRegex = + new RegexValidator(DOMAIN_NAME_REGEX); + /** + * RegexValidator for matching the a local hostname + */ + private final RegexValidator hostnameRegex = + new RegexValidator(DOMAIN_LABEL_REGEX); + + /** + * Returns the singleton instance of this validator. It + * will not consider local addresses as valid. + * @return the singleton instance of this validator + */ + public static DomainValidator getInstance() { + return DOMAIN_VALIDATOR; + } + + /** + * Returns the singleton instance of this validator, + * with local validation as required. + * @param allowLocal Should local addresses be considered valid? + * @return the singleton instance of this validator + */ + public static DomainValidator getInstance(boolean allowLocal) { + if(allowLocal) { + return DOMAIN_VALIDATOR_WITH_LOCAL; + } + return DOMAIN_VALIDATOR; + } + + /** Private constructor. */ + private DomainValidator(boolean allowLocal) { + this.allowLocal = allowLocal; + } + + /** + * Returns true if the specifiedString
parses
+ * as a valid domain name with a recognized top-level domain.
+ * The parsing is case-sensitive.
+ * @param domain the parameter to check for domain name syntax
+ * @return true if the parameter is a valid domain name
+ */
+ public boolean isValid(String domain) {
+ String[] groups = domainRegex.match(domain);
+ if (groups != null && groups.length > 0) {
+ return isValidTld(groups[0]);
+ } else if(allowLocal) {
+ if (hostnameRegex.isValid(domain)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the specified String
matches any
+ * IANA-defined top-level domain. Leading dots are ignored if present.
+ * The search is case-sensitive.
+ * @param tld the parameter to check for TLD status
+ * @return true if the parameter is a TLD
+ */
+ public boolean isValidTld(String tld) {
+ if(allowLocal && isValidLocalTld(tld)) {
+ return true;
+ }
+ return isValidInfrastructureTld(tld)
+ || isValidGenericTld(tld)
+ || isValidCountryCodeTld(tld);
+ }
+
+ /**
+ * Returns true if the specified String
matches any
+ * IANA-defined infrastructure top-level domain. Leading dots are
+ * ignored if present. The search is case-sensitive.
+ * @param iTld the parameter to check for infrastructure TLD status
+ * @return true if the parameter is an infrastructure TLD
+ */
+ public boolean isValidInfrastructureTld(String iTld) {
+ return INFRASTRUCTURE_TLD_LIST.contains(chompLeadingDot(iTld.toLowerCase()));
+ }
+
+ /**
+ * Returns true if the specified String
matches any
+ * IANA-defined generic top-level domain. Leading dots are ignored
+ * if present. The search is case-sensitive.
+ * @param gTld the parameter to check for generic TLD status
+ * @return true if the parameter is a generic TLD
+ */
+ public boolean isValidGenericTld(String gTld) {
+ return GENERIC_TLD_LIST.contains(chompLeadingDot(gTld.toLowerCase()));
+ }
+
+ /**
+ * Returns true if the specified String
matches any
+ * IANA-defined country code top-level domain. Leading dots are
+ * ignored if present. The search is case-sensitive.
+ * @param ccTld the parameter to check for country code TLD status
+ * @return true if the parameter is a country code TLD
+ */
+ public boolean isValidCountryCodeTld(String ccTld) {
+ return COUNTRY_CODE_TLD_LIST.contains(chompLeadingDot(ccTld.toLowerCase()));
+ }
+
+ /**
+ * Returns true if the specified String
matches any
+ * widely used "local" domains (localhost or localdomain). Leading dots are
+ * ignored if present. The search is case-sensitive.
+ * @param iTld the parameter to check for local TLD status
+ * @return true if the parameter is an local TLD
+ */
+ public boolean isValidLocalTld(String iTld) {
+ return LOCAL_TLD_LIST.contains(chompLeadingDot(iTld.toLowerCase()));
+ }
+
+ private String chompLeadingDot(String str) {
+ if (str.startsWith(".")) {
+ return str.substring(1);
+ } else {
+ return str;
+ }
+ }
+
+ // ---------------------------------------------
+ // ----- TLDs defined by IANA
+ // ----- Authoritative and comprehensive list at:
+ // ----- http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+
+ private static final String[] INFRASTRUCTURE_TLDS = new String[] {
+ "arpa", // internet infrastructure
+ "root" // diagnostic marker for non-truncated root zone
+ };
+
+ private static final String[] GENERIC_TLDS = new String[] {
+ "aero", // air transport industry
+ "asia", // Pan-Asia/Asia Pacific
+ "biz", // businesses
+ "cat", // Catalan linguistic/cultural community
+ "com", // commercial enterprises
+ "coop", // cooperative associations
+ "info", // informational sites
+ "jobs", // Human Resource managers
+ "mobi", // mobile products and services
+ "museum", // museums, surprisingly enough
+ "name", // individuals' sites
+ "net", // internet support infrastructure/business
+ "org", // noncommercial organizations
+ "pro", // credentialed professionals and entities
+ "tel", // contact data for businesses and individuals
+ "travel", // entities in the travel industry
+ "gov", // United States Government
+ "edu", // accredited postsecondary US education entities
+ "mil", // United States Military
+ "int" // organizations established by international treaty
+ };
+
+ private static final String[] COUNTRY_CODE_TLDS = new String[] {
+ "ac", // Ascension Island
+ "ad", // Andorra
+ "ae", // United Arab Emirates
+ "af", // Afghanistan
+ "ag", // Antigua and Barbuda
+ "ai", // Anguilla
+ "al", // Albania
+ "am", // Armenia
+ "an", // Netherlands Antilles
+ "ao", // Angola
+ "aq", // Antarctica
+ "ar", // Argentina
+ "as", // American Samoa
+ "at", // Austria
+ "au", // Australia (includes Ashmore and Cartier Islands and Coral Sea Islands)
+ "aw", // Aruba
+ "ax", // Åland
+ "az", // Azerbaijan
+ "ba", // Bosnia and Herzegovina
+ "bb", // Barbados
+ "bd", // Bangladesh
+ "be", // Belgium
+ "bf", // Burkina Faso
+ "bg", // Bulgaria
+ "bh", // Bahrain
+ "bi", // Burundi
+ "bj", // Benin
+ "bm", // Bermuda
+ "bn", // Brunei Darussalam
+ "bo", // Bolivia
+ "br", // Brazil
+ "bs", // Bahamas
+ "bt", // Bhutan
+ "bv", // Bouvet Island
+ "bw", // Botswana
+ "by", // Belarus
+ "bz", // Belize
+ "ca", // Canada
+ "cc", // Cocos (Keeling) Islands
+ "cd", // Democratic Republic of the Congo (formerly Zaire)
+ "cf", // Central African Republic
+ "cg", // Republic of the Congo
+ "ch", // Switzerland
+ "ci", // Côte d'Ivoire
+ "ck", // Cook Islands
+ "cl", // Chile
+ "cm", // Cameroon
+ "cn", // China, mainland
+ "co", // Colombia
+ "cr", // Costa Rica
+ "cu", // Cuba
+ "cv", // Cape Verde
+ "cx", // Christmas Island
+ "cy", // Cyprus
+ "cz", // Czech Republic
+ "de", // Germany
+ "dj", // Djibouti
+ "dk", // Denmark
+ "dm", // Dominica
+ "do", // Dominican Republic
+ "dz", // Algeria
+ "ec", // Ecuador
+ "ee", // Estonia
+ "eg", // Egypt
+ "er", // Eritrea
+ "es", // Spain
+ "et", // Ethiopia
+ "eu", // European Union
+ "fi", // Finland
+ "fj", // Fiji
+ "fk", // Falkland Islands
+ "fm", // Federated States of Micronesia
+ "fo", // Faroe Islands
+ "fr", // France
+ "ga", // Gabon
+ "gb", // Great Britain (United Kingdom)
+ "gd", // Grenada
+ "ge", // Georgia
+ "gf", // French Guiana
+ "gg", // Guernsey
+ "gh", // Ghana
+ "gi", // Gibraltar
+ "gl", // Greenland
+ "gm", // The Gambia
+ "gn", // Guinea
+ "gp", // Guadeloupe
+ "gq", // Equatorial Guinea
+ "gr", // Greece
+ "gs", // South Georgia and the South Sandwich Islands
+ "gt", // Guatemala
+ "gu", // Guam
+ "gw", // Guinea-Bissau
+ "gy", // Guyana
+ "hk", // Hong Kong
+ "hm", // Heard Island and McDonald Islands
+ "hn", // Honduras
+ "hr", // Croatia (Hrvatska)
+ "ht", // Haiti
+ "hu", // Hungary
+ "id", // Indonesia
+ "ie", // Ireland (Éire)
+ "il", // Israel
+ "im", // Isle of Man
+ "in", // India
+ "io", // British Indian Ocean Territory
+ "iq", // Iraq
+ "ir", // Iran
+ "is", // Iceland
+ "it", // Italy
+ "je", // Jersey
+ "jm", // Jamaica
+ "jo", // Jordan
+ "jp", // Japan
+ "ke", // Kenya
+ "kg", // Kyrgyzstan
+ "kh", // Cambodia (Khmer)
+ "ki", // Kiribati
+ "km", // Comoros
+ "kn", // Saint Kitts and Nevis
+ "kp", // North Korea
+ "kr", // South Korea
+ "kw", // Kuwait
+ "ky", // Cayman Islands
+ "kz", // Kazakhstan
+ "la", // Laos (currently being marketed as the official domain for Los Angeles)
+ "lb", // Lebanon
+ "lc", // Saint Lucia
+ "li", // Liechtenstein
+ "lk", // Sri Lanka
+ "lr", // Liberia
+ "ls", // Lesotho
+ "lt", // Lithuania
+ "lu", // Luxembourg
+ "lv", // Latvia
+ "ly", // Libya
+ "ma", // Morocco
+ "mc", // Monaco
+ "md", // Moldova
+ "me", // Montenegro
+ "mg", // Madagascar
+ "mh", // Marshall Islands
+ "mk", // Republic of Macedonia
+ "ml", // Mali
+ "mm", // Myanmar
+ "mn", // Mongolia
+ "mo", // Macau
+ "mp", // Northern Mariana Islands
+ "mq", // Martinique
+ "mr", // Mauritania
+ "ms", // Montserrat
+ "mt", // Malta
+ "mu", // Mauritius
+ "mv", // Maldives
+ "mw", // Malawi
+ "mx", // Mexico
+ "my", // Malaysia
+ "mz", // Mozambique
+ "na", // Namibia
+ "nc", // New Caledonia
+ "ne", // Niger
+ "nf", // Norfolk Island
+ "ng", // Nigeria
+ "ni", // Nicaragua
+ "nl", // Netherlands
+ "no", // Norway
+ "np", // Nepal
+ "nr", // Nauru
+ "nu", // Niue
+ "nz", // New Zealand
+ "om", // Oman
+ "pa", // Panama
+ "pe", // Peru
+ "pf", // French Polynesia With Clipperton Island
+ "pg", // Papua New Guinea
+ "ph", // Philippines
+ "pk", // Pakistan
+ "pl", // Poland
+ "pm", // Saint-Pierre and Miquelon
+ "pn", // Pitcairn Islands
+ "pr", // Puerto Rico
+ "ps", // Palestinian territories (PA-controlled West Bank and Gaza Strip)
+ "pt", // Portugal
+ "pw", // Palau
+ "py", // Paraguay
+ "qa", // Qatar
+ "re", // Réunion
+ "ro", // Romania
+ "rs", // Serbia
+ "ru", // Russia
+ "rw", // Rwanda
+ "sa", // Saudi Arabia
+ "sb", // Solomon Islands
+ "sc", // Seychelles
+ "sd", // Sudan
+ "se", // Sweden
+ "sg", // Singapore
+ "sh", // Saint Helena
+ "si", // Slovenia
+ "sj", // Svalbard and Jan Mayen Islands Not in use (Norwegian dependencies; see .no)
+ "sk", // Slovakia
+ "sl", // Sierra Leone
+ "sm", // San Marino
+ "sn", // Senegal
+ "so", // Somalia
+ "sr", // Suriname
+ "st", // São Tomé and Príncipe
+ "su", // Soviet Union (deprecated)
+ "sv", // El Salvador
+ "sy", // Syria
+ "sz", // Swaziland
+ "tc", // Turks and Caicos Islands
+ "td", // Chad
+ "tf", // French Southern and Antarctic Lands
+ "tg", // Togo
+ "th", // Thailand
+ "tj", // Tajikistan
+ "tk", // Tokelau
+ "tl", // East Timor (deprecated old code)
+ "tm", // Turkmenistan
+ "tn", // Tunisia
+ "to", // Tonga
+ "tp", // East Timor
+ "tr", // Turkey
+ "tt", // Trinidad and Tobago
+ "tv", // Tuvalu
+ "tw", // Taiwan, Republic of China
+ "tz", // Tanzania
+ "ua", // Ukraine
+ "ug", // Uganda
+ "uk", // United Kingdom
+ "um", // United States Minor Outlying Islands
+ "us", // United States of America
+ "uy", // Uruguay
+ "uz", // Uzbekistan
+ "va", // Vatican City State
+ "vc", // Saint Vincent and the Grenadines
+ "ve", // Venezuela
+ "vg", // British Virgin Islands
+ "vi", // U.S. Virgin Islands
+ "vn", // Vietnam
+ "vu", // Vanuatu
+ "wf", // Wallis and Futuna
+ "ws", // Samoa (formerly Western Samoa)
+ "ye", // Yemen
+ "yt", // Mayotte
+ "yu", // Serbia and Montenegro (originally Yugoslavia)
+ "za", // South Africa
+ "zm", // Zambia
+ "zw", // Zimbabwe
+ };
+
+ private static final String[] LOCAL_TLDS = new String[] {
+ "localhost", // RFC2606 defined
+ "localdomain" // Also widely used as localhost.localdomain
+ };
+
+ private static final ListPerform email validations.
+ *+ * This class is a Singleton; you can retrieve the instance via the getInstance() method. + *
+ *+ * Based on a script by Sandeep V. Tamhankar + * http://javascript.internet.com + *
+ *+ * This implementation is not guaranteed to catch all possible errors in an email address. + * For example, an address like nobody@noplace.somedog will pass validator, even though there + * is no TLD "somedog" + *
. + * + * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $ + * @since Validator 1.4 + */ +public class EmailValidator extends AbstractValidator { + + private static final String SPECIAL_CHARS = "\\p{Cntrl}\\(\\)<>@,;:'\\\\\\\"\\.\\[\\]"; + private static final String VALID_CHARS = "[^\\s" + SPECIAL_CHARS + "]"; + private static final String QUOTED_USER = "(\"[^\"]*\")"; + private static final String WORD = "((" + VALID_CHARS + "|')+|" + QUOTED_USER + ")"; + + private static final String LEGAL_ASCII_REGEX = "^\\p{ASCII}+$"; + private static final String EMAIL_REGEX = "^\\s*?(.+)@(.+?)\\s*$"; + private static final String IP_DOMAIN_REGEX = "^\\[(.*)\\]$"; + private static final String USER_REGEX = "^\\s*" + WORD + "(\\." + WORD + ")*$"; + + private static final Pattern MATCH_ASCII_PATTERN = Pattern.compile(LEGAL_ASCII_REGEX); + private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX); + private static final Pattern IP_DOMAIN_PATTERN = Pattern.compile(IP_DOMAIN_REGEX); + private static final Pattern USER_PATTERN = Pattern.compile(USER_REGEX); + + private final boolean allowLocal; + + /** + * Singleton instance of this class, which + * doesn't consider local addresses as valid. + */ + private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator(false); + + /** + * Singleton instance of this class, which does + * consider local addresses valid. + */ + private static final EmailValidator EMAIL_VALIDATOR_WITH_LOCAL = new EmailValidator(true); + + /** + * Returns the Singleton instance of this validator. + * + * @return singleton instance of this validator. + */ + public static EmailValidator getInstance() { + return EMAIL_VALIDATOR; + } + + /** + * Returns the Singleton instance of this validator, + * with local validation as required. + * + * @param allowLocal Should local addresses be considered valid? + * @return singleton instance of this validator + */ + public static EmailValidator getInstance(boolean allowLocal) { + if(allowLocal) { + return EMAIL_VALIDATOR_WITH_LOCAL; + } + return EMAIL_VALIDATOR; + } + + /** + * Protected constructor for subclasses to use. + * + * @param allowLocal Should local addresses be considered valid? + */ + protected EmailValidator(boolean allowLocal) { + super(); + this.allowLocal = allowLocal; + } + + /** + *Checks if a field has a valid e-mail address.
+ * + * @param email The value validation is being performed on. Anull
+ * value is considered invalid.
+ * @return true if the email address is valid.
+ */
+ @Override
+ public boolean isValid(String email) {
+ if (email == null) {
+ return false;
+ }
+
+ Matcher asciiMatcher = MATCH_ASCII_PATTERN.matcher(email);
+ if (!asciiMatcher.matches()) {
+ setErrorMessage(tr("E-mail address contains non-ascii characters"));
+ setFix(email.replaceAll("[^\\p{ASCII}]+", ""));
+ return false;
+ }
+
+ // Check the whole email address structure
+ Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
+ if (!emailMatcher.matches()) {
+ setErrorMessage(tr("E-mail address is invalid"));
+ return false;
+ }
+
+ if (email.endsWith(".")) {
+ setErrorMessage(tr("E-mail address is invalid"));
+ return false;
+ }
+
+ String username = emailMatcher.group(1);
+ if (!isValidUser(username)) {
+ setErrorMessage(tr("E-mail address contains an invalid username: {0}", username));
+ return false;
+ }
+
+ String domain = emailMatcher.group(2);
+ if (!isValidDomain(domain)) {
+ setErrorMessage(tr("E-mail address contains an invalid domain: {0}", domain));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the domain component of an email address is valid.
+ *
+ * @param domain being validated.
+ * @return true if the email address's domain is valid.
+ */
+ protected boolean isValidDomain(String domain) {
+ // see if domain is an IP address in brackets
+ Matcher ipDomainMatcher = IP_DOMAIN_PATTERN.matcher(domain);
+
+ if (ipDomainMatcher.matches()) {
+ InetAddressValidator inetAddressValidator =
+ InetAddressValidator.getInstance();
+ return inetAddressValidator.isValid(ipDomainMatcher.group(1));
+ } else {
+ // Domain is symbolic name
+ DomainValidator domainValidator =
+ DomainValidator.getInstance(allowLocal);
+ return domainValidator.isValid(domain);
+ }
+ }
+
+ /**
+ * Returns true if the user component of an email address is valid.
+ *
+ * @param user being validated
+ * @return true if the user name is valid.
+ */
+ protected boolean isValidUser(String user) {
+ return USER_PATTERN.matcher(user).matches();
+ }
+
+}
Index: /trunk/src/org/openstreetmap/josm/data/validation/routines/InetAddressValidator.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/routines/InetAddressValidator.java (revision 7489)
+++ /trunk/src/org/openstreetmap/josm/data/validation/routines/InetAddressValidator.java (revision 7489)
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.data.validation.routines;
+
+/**
+ * InetAddress validation and conversion routines (java.net.InetAddress
).
This class provides methods to validate a candidate IP address. + * + *
+ * This class is a Singleton; you can retrieve the instance via the {@link #getInstance()} method. + *
+ * + * @version $Revision: 1227719 $ + * @since Validator 1.4 + */ +public class InetAddressValidator extends AbstractValidator { + + private static final String IPV4_REGEX = + "^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$"; + + /** + * Singleton instance of this class. + */ + private static final InetAddressValidator VALIDATOR = new InetAddressValidator(); + + /** IPv4 RegexValidator */ + private final RegexValidator ipv4Validator = new RegexValidator(IPV4_REGEX); + + /** + * Returns the singleton instance of this validator. + * @return the singleton instance of this validator + */ + public static InetAddressValidator getInstance() { + return VALIDATOR; + } + + /** + * Checks if the specified string is a valid IP address. + * @param inetAddress the string to validate + * @return true if the string validates as an IP address + */ + public boolean isValid(String inetAddress) { + return isValidInet4Address(inetAddress); + } + + /** + * Validates an IPv4 address. Returns true if valid. + * @param inet4Address the IPv4 address to validate + * @return true if the argument contains a valid IPv4 address + */ + public boolean isValidInet4Address(String inet4Address) { + // verify that address conforms to generic IPv4 format + String[] groups = ipv4Validator.match(inet4Address); + + if (groups == null) return false; + + // verify that address subgroups are legal + for (int i = 0; i <= 3; i++) { + String ipSegment = groups[i]; + if (ipSegment == null || ipSegment.length() <= 0) { + return false; + } + + int iIpSegment = 0; + + try { + iIpSegment = Integer.parseInt(ipSegment); + } catch(NumberFormatException e) { + return false; + } + + if (iIpSegment > 255) { + return false; + } + + } + + return true; + } +} Index: /trunk/src/org/openstreetmap/josm/data/validation/routines/RegexValidator.java =================================================================== --- /trunk/src/org/openstreetmap/josm/data/validation/routines/RegexValidator.java (revision 7489) +++ /trunk/src/org/openstreetmap/josm/data/validation/routines/RegexValidator.java (revision 7489) @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openstreetmap.josm.data.validation.routines; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Regular Expression validation (using JDK 1.4+ regex support). + *+ * Construct the validator either for a single regular expression or a set (array) of + * regular expressions. By default validation is case sensitive but constructors + * are provided to allow case in-sensitive validation. For example to create + * a validator which does case in-sensitive validation for a set of regular + * expressions: + *
+ * String[] regexs = new String[] {...}; + * RegexValidator validator = new RegexValidator(regexs, false); + *+ *
+ *
true
or false
:boolean valid = validator.isValid(value);
String result = validator.validate(value);
String[] result = validator.match(value);
+ * Cached instances pre-compile and re-use {@link Pattern}(s) - which according
+ * to the {@link Pattern} API are safe to use in a multi-threaded environment.
+ *
+ * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $
+ * @since Validator 1.4
+ */
+public class RegexValidator extends AbstractValidator {
+
+ private final Pattern[] patterns;
+
+ /**
+ * Construct a case sensitive validator for a single
+ * regular expression.
+ *
+ * @param regex The regular expression this validator will
+ * validate against
+ */
+ public RegexValidator(String regex) {
+ this(regex, true);
+ }
+
+ /**
+ * Construct a validator for a single regular expression
+ * with the specified case sensitivity.
+ *
+ * @param regex The regular expression this validator will
+ * validate against
+ * @param caseSensitive when true
matching is case
+ * sensitive, otherwise matching is case in-sensitive
+ */
+ public RegexValidator(String regex, boolean caseSensitive) {
+ this(new String[] {regex}, caseSensitive);
+ }
+
+ /**
+ * Construct a case sensitive validator that matches any one
+ * of the set of regular expressions.
+ *
+ * @param regexs The set of regular expressions this validator will
+ * validate against
+ */
+ public RegexValidator(String[] regexs) {
+ this(regexs, true);
+ }
+
+ /**
+ * Construct a validator that matches any one of the set of regular
+ * expressions with the specified case sensitivity.
+ *
+ * @param regexs The set of regular expressions this validator will
+ * validate against
+ * @param caseSensitive when true
matching is case
+ * sensitive, otherwise matching is case in-sensitive
+ */
+ public RegexValidator(String[] regexs, boolean caseSensitive) {
+ if (regexs == null || regexs.length == 0) {
+ throw new IllegalArgumentException("Regular expressions are missing");
+ }
+ patterns = new Pattern[regexs.length];
+ int flags = (caseSensitive ? 0: Pattern.CASE_INSENSITIVE);
+ for (int i = 0; i < regexs.length; i++) {
+ if (regexs[i] == null || regexs[i].length() == 0) {
+ throw new IllegalArgumentException("Regular expression[" + i + "] is missing");
+ }
+ patterns[i] = Pattern.compile(regexs[i], flags);
+ }
+ }
+
+ /**
+ * Validate a value against the set of regular expressions.
+ *
+ * @param value The value to validate.
+ * @return true
if the value is valid
+ * otherwise false
.
+ */
+ public boolean isValid(String value) {
+ if (value == null) {
+ return false;
+ }
+ for (int i = 0; i < patterns.length; i++) {
+ if (patterns[i].matcher(value).matches()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Validate a value against the set of regular expressions
+ * returning the array of matched groups.
+ *
+ * @param value The value to validate.
+ * @return String array of the groups matched if
+ * valid or null
if invalid
+ */
+ public String[] match(String value) {
+ if (value == null) {
+ return null;
+ }
+ for (int i = 0; i < patterns.length; i++) {
+ Matcher matcher = patterns[i].matcher(value);
+ if (matcher.matches()) {
+ int count = matcher.groupCount();
+ String[] groups = new String[count];
+ for (int j = 0; j < count; j++) {
+ groups[j] = matcher.group(j+1);
+ }
+ return groups;
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Validate a value against the set of regular expressions
+ * returning a String value of the aggregated groups.
+ *
+ * @param value The value to validate.
+ * @return Aggregated String value comprised of the
+ * groups matched if valid or null
if invalid
+ */
+ public String validate(String value) {
+ if (value == null) {
+ return null;
+ }
+ for (int i = 0; i < patterns.length; i++) {
+ Matcher matcher = patterns[i].matcher(value);
+ if (matcher.matches()) {
+ int count = matcher.groupCount();
+ if (count == 1) {
+ return matcher.group(1);
+ }
+ StringBuffer buffer = new StringBuffer();
+ for (int j = 0; j < count; j++) {
+ String component = matcher.group(j+1);
+ if (component != null) {
+ buffer.append(component);
+ }
+ }
+ return buffer.toString();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Provide a String representation of this validator.
+ * @return A String representation of this validator
+ */
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("RegexValidator{");
+ for (int i = 0; i < patterns.length; i++) {
+ if (i > 0) {
+ buffer.append(",");
+ }
+ buffer.append(patterns[i].pattern());
+ }
+ buffer.append("}");
+ return buffer.toString();
+ }
+
+}
Index: /trunk/src/org/openstreetmap/josm/data/validation/routines/UrlValidator.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/routines/UrlValidator.java (revision 7489)
+++ /trunk/src/org/openstreetmap/josm/data/validation/routines/UrlValidator.java (revision 7489)
@@ -0,0 +1,512 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openstreetmap.josm.data.validation.routines;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
URL Validation routines.
+ * Behavior of validation is modified by passing in options: + *Originally based in on php script by Debbie Dyer, validation.php v1.2b, Date: 03/07/02, + * http://javascript.internet.com. However, this validation now bears little resemblance + * to the php original.
+ *+ * Example of usage: + * Construct a UrlValidator with valid schemes of "http", and "https". + * + * String[] schemes = {"http","https"}. + * UrlValidator urlValidator = new UrlValidator(schemes); + * if (urlValidator.isValid("ftp://foo.bar.com/")) { + * System.out.println("url is valid"); + * } else { + * System.out.println("url is invalid"); + * } + * + * prints "url is invalid" + * If instead the default constructor is used. + * + * UrlValidator urlValidator = new UrlValidator(); + * if (urlValidator.isValid("ftp://foo.bar.com/")) { + * System.out.println("url is valid"); + * } else { + * System.out.println("url is invalid"); + * } + * + * prints out "url is valid" + *+ * + * @see + * + * Uniform Resource Identifiers (URI): Generic Syntax + * + * + * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $ + * @since Validator 1.4 + */ +public class UrlValidator extends AbstractValidator { + + /** + * Allows all validly formatted schemes to pass validation instead of + * supplying a set of valid schemes. + */ + public static final long ALLOW_ALL_SCHEMES = 1 << 0; + + /** + * Allow two slashes in the path component of the URL. + */ + public static final long ALLOW_2_SLASHES = 1 << 1; + + /** + * Enabling this options disallows any URL fragments. + */ + public static final long NO_FRAGMENTS = 1 << 2; + + /** + * Allow local URLs, such as http://localhost/ or http://machine/ . + * This enables a broad-brush check, for complex local machine name + * validation requirements you should create your validator with + * a {@link RegexValidator} instead ({@link #UrlValidator(RegexValidator, long)}) + */ + public static final long ALLOW_LOCAL_URLS = 1 << 3; + + // Drop numeric, and "+-." for now + private static final String AUTHORITY_CHARS_REGEX = "\\p{Alnum}\\-\\."; + + /** + * This expression derived/taken from the BNF for URI (RFC2396). + */ + private static final String URL_REGEX = + "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; + + private static final Pattern URL_PATTERN = Pattern.compile(URL_REGEX); + + /** + * Schema/Protocol (ie. http:, ftp:, file:, etc). + */ + private static final int PARSE_URL_SCHEME = 2; + + /** + * Includes hostname/ip and port number. + */ + private static final int PARSE_URL_AUTHORITY = 4; + + private static final int PARSE_URL_PATH = 5; + + private static final int PARSE_URL_QUERY = 7; + + private static final int PARSE_URL_FRAGMENT = 9; + + /** + * Protocol (ie. http:, ftp:,https:). + */ + private static final String SCHEME_REGEX = "^\\p{Alpha}[\\p{Alnum}\\+\\-\\.]*"; + private static final Pattern SCHEME_PATTERN = Pattern.compile(SCHEME_REGEX); + + private static final String AUTHORITY_REGEX = + "^([" + AUTHORITY_CHARS_REGEX + "]*)(:\\d*)?(.*)?"; + + private static final Pattern AUTHORITY_PATTERN = Pattern.compile(AUTHORITY_REGEX); + + private static final int PARSE_AUTHORITY_HOST_IP = 1; + + private static final int PARSE_AUTHORITY_PORT = 2; + + /** + * Should always be empty. + */ + private static final int PARSE_AUTHORITY_EXTRA = 3; + + private static final String PATH_REGEX = "^(/[-\\w:@&?=+,.!/~*'%$_;\\(\\)]*)?$"; + private static final Pattern PATH_PATTERN = Pattern.compile(PATH_REGEX); + + private static final String QUERY_REGEX = "^(.*)$"; + private static final Pattern QUERY_PATTERN = Pattern.compile(QUERY_REGEX); + + private static final String LEGAL_ASCII_REGEX = "^\\p{ASCII}+$"; + private static final Pattern ASCII_PATTERN = Pattern.compile(LEGAL_ASCII_REGEX); + + private static final String PORT_REGEX = "^:(\\d{1,5})$"; + private static final Pattern PORT_PATTERN = Pattern.compile(PORT_REGEX); + + /** + * Holds the set of current validation options. + */ + private final long options; + + /** + * The set of schemes that are allowed to be in a URL. + */ + private final Set
ALLOW_2_SLASHES + NO_FRAGMENTS
ALLOW_2_SLASHES + NO_FRAGMENTS
Checks if a field has a valid url address.
+ * + * @param value The value validation is being performed on. Anull
+ * value is considered invalid.
+ * @return true if the url is valid.
+ */
+ @Override
+ public boolean isValid(String value) {
+ if (value == null) {
+ return false;
+ }
+
+ if (!ASCII_PATTERN.matcher(value).matches()) {
+ setErrorMessage(tr("URL contains non-ascii characters"));
+ setFix(value.replaceAll("[^\\p{ASCII}]+", ""));
+ return false;
+ }
+
+ // Check the whole url address structure
+ Matcher urlMatcher = URL_PATTERN.matcher(value);
+ if (!urlMatcher.matches()) {
+ setErrorMessage(tr("URL is invalid"));
+ return false;
+ }
+
+ String scheme = urlMatcher.group(PARSE_URL_SCHEME);
+ if (!isValidScheme(scheme)) {
+ setErrorMessage(tr("URL contains an invalid protocol: {0}", scheme));
+ return false;
+ }
+
+ String authority = urlMatcher.group(PARSE_URL_AUTHORITY);
+ if ("file".equals(scheme) && "".equals(authority)) {
+ // Special case - file: allows an empty authority
+ } else {
+ // Validate the authority
+ if (!isValidAuthority(authority)) {
+ setErrorMessage(tr("URL contains an invalid authority: {0}", authority));
+ return false;
+ }
+ }
+
+ String path = urlMatcher.group(PARSE_URL_PATH);
+ if (!isValidPath(path)) {
+ setErrorMessage(tr("URL contains an invalid path: {0}", path));
+ return false;
+ }
+
+ String query = urlMatcher.group(PARSE_URL_QUERY);
+ if (!isValidQuery(query)) {
+ setErrorMessage(tr("URL contains an invalid query: {0}", query));
+ return false;
+ }
+
+ String fragment = urlMatcher.group(PARSE_URL_FRAGMENT);
+ if (!isValidFragment(fragment)) {
+ setErrorMessage(tr("URL contains an invalid fragment: {0}", fragment));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Validate scheme. If schemes[] was initialized to a non null,
+ * then only those scheme's are allowed. Note this is slightly different
+ * than for the constructor.
+ * @param scheme The scheme to validate. A null
value is considered
+ * invalid.
+ * @return true if valid.
+ */
+ protected boolean isValidScheme(String scheme) {
+ if (scheme == null) {
+ return false;
+ }
+
+ if (!SCHEME_PATTERN.matcher(scheme).matches()) {
+ return false;
+ }
+
+ if (isOff(ALLOW_ALL_SCHEMES)) {
+
+ if (!this.allowedSchemes.contains(scheme)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the authority is properly formatted. An authority is the combination
+ * of hostname and port. A null
authority value is considered invalid.
+ * @param authority Authority value to validate.
+ * @return true if authority (hostname and port) is valid.
+ */
+ protected boolean isValidAuthority(String authority) {
+ if (authority == null) {
+ return false;
+ }
+
+ // check manual authority validation if specified
+ if (authorityValidator != null) {
+ if (authorityValidator.isValid(authority)) {
+ return true;
+ }
+ }
+
+ Matcher authorityMatcher = AUTHORITY_PATTERN.matcher(authority);
+ if (!authorityMatcher.matches()) {
+ return false;
+ }
+
+ String hostLocation = authorityMatcher.group(PARSE_AUTHORITY_HOST_IP);
+ // check if authority is hostname or IP address:
+ // try a hostname first since that's much more likely
+ DomainValidator domainValidator = DomainValidator.getInstance(isOn(ALLOW_LOCAL_URLS));
+ if (!domainValidator.isValid(hostLocation)) {
+ // try an IP address
+ InetAddressValidator inetAddressValidator =
+ InetAddressValidator.getInstance();
+ if (!inetAddressValidator.isValid(hostLocation)) {
+ // isn't either one, so the URL is invalid
+ return false;
+ }
+ }
+
+ String port = authorityMatcher.group(PARSE_AUTHORITY_PORT);
+ if (port != null) {
+ if (!PORT_PATTERN.matcher(port).matches()) {
+ return false;
+ }
+ }
+
+ String extra = authorityMatcher.group(PARSE_AUTHORITY_EXTRA);
+ if (extra != null && extra.trim().length() > 0){
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the path is valid. A null
value is considered invalid.
+ * @param path Path value to validate.
+ * @return true if path is valid.
+ */
+ protected boolean isValidPath(String path) {
+ if (path == null) {
+ return false;
+ }
+
+ if (!PATH_PATTERN.matcher(path).matches()) {
+ return false;
+ }
+
+ int slash2Count = countToken("//", path);
+ if (isOff(ALLOW_2_SLASHES) && (slash2Count > 0)) {
+ return false;
+ }
+
+ int slashCount = countToken("/", path);
+ int dot2Count = countToken("..", path);
+ if (dot2Count > 0) {
+ if ((slashCount - slash2Count - 1) <= dot2Count) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the query is null or it's a properly formatted query string.
+ * @param query Query value to validate.
+ * @return true if query is valid.
+ */
+ protected boolean isValidQuery(String query) {
+ if (query == null) {
+ return true;
+ }
+
+ return QUERY_PATTERN.matcher(query).matches();
+ }
+
+ /**
+ * Returns true if the given fragment is null or fragments are allowed.
+ * @param fragment Fragment value to validate.
+ * @return true if fragment is valid.
+ */
+ protected boolean isValidFragment(String fragment) {
+ if (fragment == null) {
+ return true;
+ }
+
+ return isOff(NO_FRAGMENTS);
+ }
+
+ /**
+ * Returns the number of times the token appears in the target.
+ * @param token Token value to be counted.
+ * @param target Target value to count tokens in.
+ * @return the number of tokens.
+ */
+ protected int countToken(String token, String target) {
+ int tokenIndex = 0;
+ int count = 0;
+ while (tokenIndex != -1) {
+ tokenIndex = target.indexOf(token, tokenIndex);
+ if (tokenIndex > -1) {
+ tokenIndex++;
+ count++;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Tests whether the given flag is on. If the flag is not a power of 2
+ * (ie. 3) this tests whether the combination of flags is on.
+ *
+ * @param flag Flag value to check.
+ *
+ * @return whether the specified flag value is on.
+ */
+ private boolean isOn(long flag) {
+ return (this.options & flag) > 0;
+ }
+
+ /**
+ * Tests whether the given flag is off. If the flag is not a power of 2
+ * (ie. 3) this tests whether the combination of flags is off.
+ *
+ * @param flag Flag value to check.
+ *
+ * @return whether the specified flag value is off.
+ */
+ private boolean isOff(long flag) {
+ return (this.options & flag) == 0;
+ }
+}
Index: /trunk/src/org/openstreetmap/josm/data/validation/routines/package.html
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/routines/package.html (revision 7489)
+++ /trunk/src/org/openstreetmap/josm/data/validation/routines/package.html (revision 7489)
@@ -0,0 +1,293 @@
+
+
+
+This package contains independant validation routines adapted from Apache Commons Validator 1.4.0.
++ Commons Validator serves two purposes: +
++ This package has been created, since version 1.3.0, in an attempt to clearly + separate these two concerns and is the location for the standard, independant + validation routines/functions in Commons Validator. +
+ ++ The contents of this package have no dependencies on the framework aspect of + Commons Validator and can be used on their own. +
+ + ++ This section lists other available validators. +
++ Regular expression validation can be done either by using the static + methods provied by RegexValidator or + by creating a new instance, which caches and re-uses compiled Patterns. +
+isValid()
methods return true/false to indicate
+ whether validation was successful.validate()
methods return a String
+ value of the matched groups aggregated together or
+ null
if invalid.match()
methods return a String
array
+ of the matched groups or null
if invalid.+ Below is an example of using one of the static methods to validate, + matching in a case insensitive manner and returning a String + of the matched groups (which doesn't include the hyphen). +
++ // set up the parameters + boolean caseSensitive = false; + String regex = "^([A-Z]*)(?:\\-)([A-Z]*)$"; + + // validate - result should be a String of value "abcdef" + String result = RegexValidator.validate("abc-def", regex, caseSensitive); + ++ +
The following static methods are provided for regular expression validation: +
+isValid(value, regex)
isValid(value, regex, caseSensitive)
validate(value, regex)
validate(value, regex, caseSensitive)
match(value, regex)
match(value, regex, caseSensitive)
+ Below is an example of creating an instance of + RegexValidator matching in a case insensitive + manner against a set of regular expressions: +
++ // set up the parameters + boolean caseSensitive = false; + String regex1 = "^([A-Z]*)(?:\\-)([A-Z]*)*$" + String regex2 = "^([A-Z]*)$"; + String[] regexs = new String[] {regex1, regex1}; + + // Create the validator + RegexValidator validator = new RegexValidator(regexs, caseSensitive); + + // Validate true/false + boolean valid = validator.isValid("abc-def"); + + // Validate and return a String + String result = validator.validate("abc-def"); + + // Validate and return a String[] + String[] groups = validator.match("abc-def"); + ++
See the + RegexValidator javadoc for a full list + of the available constructors. +
+ + ++ InetAddressValidator provides + IPv4 address validation. +
++ For example: +
++ + // Get an InetAddressValidator + InetAddressValidator validator = InetAddressValidator.getInstance(); + + // Validate an IPv4 address + if (!validator.isValid(candidateInetAddress)) { + ... // invalid + } + ++ + +
+ EmailValidator provides email address + validation according to RFC 822 standards. +
++ For example: +
++ // Get an EmailValidator + EmailValidator validator = EmailValidator.getInstance(); + + // Validate an email address + boolean isAddressValid = validator.isValid("user@apache.org"); + + // Validate a variable containing an email address + if (!validator.isValid(addressFromUserForm)) { + webController.sendRedirect(ERROR_REDIRECT, "Email address isn't valid"); + // etc. + } ++ + +
+ UrlValidator provides URL validation by + checking the scheme, authority, path, query, and fragment in turn. Clients + may specify valid schemes to be used in validating in addition to or instead of + the default values (HTTP, HTTPS, FTP). The UrlValidator also supports options + that change the parsing rules; for example, the ALLOW_2_SLASHES option instructs + the Validator to allow consecutive slash characters in the path component, which + is considered an error by default. + + For more information on the available options, see the UrlValidator documentation. +
++ For example: +
++ // Get an UrlValidator + UrlValidator defaultValidator = new UrlValidator(); // default schemes + if (defaultValidator.isValid("http://www.apache.org")) { + ... // valid + } + if (!defaultValidator.isValid("http//www.oops.com")) { + ... // invalid + } + + // Get an UrlValidator with custom schemes + String[] customSchemes = { "sftp", "scp", "https" }; + UrlValidator customValidator = new UrlValidator(customSchemes); + if (!customValidator.isValid("http://www.apache.org")) { + ... // invalid due to insecure protocol + } + + // Get an UrlValidator that allows double slashes in the path + UrlValidator doubleSlashValidator = new UrlValidator(UrlValidator.ALLOW_2_SLASHES); + if (doubleSlashValidator.isValid("http://www.apache.org//projects")) { + ... // valid only in this Validator instance + } ++ + +
+ DomainValidator provides validation of Internet + domain names as specified by RFC1034/RFC1123 and according to the IANA-recognized + list of top-level domains (TLDs). Clients may validate an entire domain name, a + TLD of any category, or a TLD within a specific category. +
++ For example: +
++ // Get a DomainValidator + DomainValidator validator = DomainValidator.getInstance(); + + // Validate a domain name + if (validator.isValid("www.apache.org")) { + ... // valid + } + if (!validator.isValid("www.apache.wrong")) { + ... // invalid + } + + // Validate a TLD + if (validator.isValidTld(".com")) { + ... // valid + } + if (validator.isValidTld("org")) { + ... // valid, the leading dot is optional + } + if (validator.isValidTld(".us")) { + ... // valid, country code TLDs are also accepted + } + + // Validate TLDs in categories + if (validator.isValidGenericTld(".name")) { + ... // valid + } + if (!validator.isValidGenericTld(".uk")) { + ... // invalid, .uk is a country code TLD + } + if (!validator.isValidCountryCodeTld(".info")) { + ... // invalid, .info is a generic TLD + } ++ + Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/InternetTags.java =================================================================== --- /trunk/src/org/openstreetmap/josm/data/validation/tests/InternetTags.java (revision 7489) +++ /trunk/src/org/openstreetmap/josm/data/validation/tests/InternetTags.java (revision 7489) @@ -0,0 +1,93 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.data.validation.tests; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import org.openstreetmap.josm.command.ChangePropertyCommand; +import org.openstreetmap.josm.data.osm.Node; +import org.openstreetmap.josm.data.osm.OsmPrimitive; +import org.openstreetmap.josm.data.osm.Relation; +import org.openstreetmap.josm.data.osm.Way; +import org.openstreetmap.josm.data.validation.FixableTestError; +import org.openstreetmap.josm.data.validation.Severity; +import org.openstreetmap.josm.data.validation.Test; +import org.openstreetmap.josm.data.validation.TestError; +import org.openstreetmap.josm.data.validation.routines.AbstractValidator; +import org.openstreetmap.josm.data.validation.routines.EmailValidator; +import org.openstreetmap.josm.data.validation.routines.UrlValidator; + +/** + * Performs validation tests on internet-related tags (websites, e-mail addresses, etc.). + * @since 7489 + */ +public class InternetTags extends Test { + + protected static final int INVALID_URL = 3301; + protected static final int INVALID_EMAIL = 3302; + + /** + * List of keys subject to URL validation. + */ + public static String[] URL_KEYS = new String[] { + "url", "source:url", + "website", "contact:website", "heritage:website", "source:website" + }; + + /** + * List of keys subject to email validation. + */ + public static String[] EMAIL_KEYS = new String[] { + "email", "contact:email" + }; + + /** + * Constructs a new {@code InternetTags} test. + */ + public InternetTags() { + super(tr("Internet tags"), tr("Checks for errors in internet-related tags.")); + } + + private boolean doTest(OsmPrimitive p, String k, String[] keys, AbstractValidator validator, int code) { + for (String i : keys) { + if (i.equals(k)) { + if (!validator.isValid(p.get(k))) { + TestError error; + String msg = tr("''{0}'': {1}", k, validator.getErrorMessage()); + String fix = validator.getFix(); + if (fix != null) { + error = new FixableTestError(this, Severity.WARNING, msg, code, p, + new ChangePropertyCommand(p, k, fix)); + } else { + error = new TestError(this, Severity.WARNING, msg, code, p); + } + return errors.add(error); + } + break; + } + } + return false; + } + + private void test(OsmPrimitive p) { + for (String k : p.keySet()) { + if (!doTest(p, k, URL_KEYS, UrlValidator.getInstance(), INVALID_URL)) { + doTest(p, k, EMAIL_KEYS, EmailValidator.getInstance(), INVALID_EMAIL); + } + } + } + + @Override + public void visit(Node n) { + test(n); + } + + @Override + public void visit(Way w) { + test(w); + } + + @Override + public void visit(Relation r) { + test(r); + } +}