001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.validation.tests; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import org.openstreetmap.josm.data.osm.Node; 007import org.openstreetmap.josm.data.osm.OsmPrimitive; 008import org.openstreetmap.josm.data.osm.Relation; 009import org.openstreetmap.josm.data.osm.Way; 010import org.openstreetmap.josm.data.validation.Severity; 011import org.openstreetmap.josm.data.validation.Test; 012import org.openstreetmap.josm.data.validation.TestError; 013import org.openstreetmap.josm.data.validation.routines.AbstractValidator; 014import org.openstreetmap.josm.data.validation.routines.EmailValidator; 015import org.openstreetmap.josm.data.validation.routines.UrlValidator; 016 017/** 018 * Performs validation tests on internet-related tags (websites, e-mail addresses, etc.). 019 * @since 7489 020 */ 021public class InternetTags extends Test { 022 023 /** Error code for an invalid URL */ 024 public static final int INVALID_URL = 3301; 025 /** Error code for an invalid e-mail */ 026 public static final int INVALID_EMAIL = 3302; 027 028 /** 029 * List of keys subject to URL validation. 030 */ 031 private static String[] URL_KEYS = new String[] { 032 "url", "source:url", 033 "website", "contact:website", "heritage:website", "source:website" 034 }; 035 036 /** 037 * List of keys subject to email validation. 038 */ 039 private static String[] EMAIL_KEYS = new String[] { 040 "email", "contact:email" 041 }; 042 043 /** 044 * Constructs a new {@code InternetTags} test. 045 */ 046 public InternetTags() { 047 super(tr("Internet tags"), tr("Checks for errors in internet-related tags.")); 048 } 049 050 /** 051 * Potentially validates a given primitive key against a given validator. 052 * @param p The OSM primitive to test 053 * @param k The key to validate 054 * @param keys The list of keys to check. If {@code k} is not inside this collection, do nothing 055 * @param validator The validator to run if {@code k} is inside {@code keys} 056 * @param code The error code to set if the validation fails 057 * @return {@code true} if the validation fails. In this case, a new error has been created. 058 */ 059 private boolean doTest(OsmPrimitive p, String k, String[] keys, AbstractValidator validator, int code) { 060 for (String i : keys) { 061 if (i.equals(k)) { 062 TestError error = validateTag(p, k, validator, code); 063 if (error != null) { 064 errors.add(error); 065 } 066 break; 067 } 068 } 069 return false; 070 } 071 072 /** 073 * Validates a given primitive tag against a given validator. 074 * @param p The OSM primitive to test 075 * @param k The key to validate 076 * @param validator The validator to run 077 * @param code The error code to set if the validation fails 078 * @return The error if the validation fails, {@code null} otherwise 079 * @since 7824 080 */ 081 public TestError validateTag(OsmPrimitive p, String k, AbstractValidator validator, int code) { 082 return doValidateTag(p, k, null, validator, code); 083 } 084 085 /** 086 * Validates a given primitive tag against a given validator. 087 * @param p The OSM primitive to test 088 * @param k The key to validate 089 * @param v The value to validate. May be {@code null} to use {@code p.get(k)} 090 * @param validator The validator to run 091 * @param code The error code to set if the validation fails 092 * @return The error if the validation fails, {@code null} otherwise 093 */ 094 private TestError doValidateTag(OsmPrimitive p, String k, String v, AbstractValidator validator, int code) { 095 TestError error = null; 096 String value = v != null ? v : p.get(k); 097 if (!validator.isValid(value)) { 098 String errMsg = validator.getErrorMessage(); 099 // Special treatment to allow URLs without protocol. See UrlValidator#isValid 100 if (tr("URL contains an invalid protocol: {0}", (String) null).equals(errMsg)) { 101 String proto = validator instanceof EmailValidator ? "mailto://" : "http://"; 102 return doValidateTag(p, k, proto+value, validator, code); 103 } 104 String msg = tr("''{0}'': {1}", k, errMsg); 105 // todo obtain English message for ignore functionality 106 error = new TestError(this, Severity.WARNING, validator.getValidatorName(), msg, msg, code, p); 107 } 108 return error; 109 } 110 111 private void test(OsmPrimitive p) { 112 for (String k : p.keySet()) { 113 // Test key against URL validator 114 if (!doTest(p, k, URL_KEYS, UrlValidator.getInstance(), INVALID_URL)) { 115 // Test key against e-mail validator only if the URL validator did not fail 116 doTest(p, k, EMAIL_KEYS, EmailValidator.getInstance(), INVALID_EMAIL); 117 } 118 } 119 } 120 121 @Override 122 public void visit(Node n) { 123 test(n); 124 } 125 126 @Override 127 public void visit(Way w) { 128 test(w); 129 } 130 131 @Override 132 public void visit(Relation r) { 133 test(r); 134 } 135}