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