001package ezvcard; 002 003import java.text.NumberFormat; 004import java.util.ArrayList; 005import java.util.IdentityHashMap; 006import java.util.Iterator; 007import java.util.List; 008import java.util.Locale; 009import java.util.Map; 010import java.util.Map.Entry; 011 012import ezvcard.property.VCardProperty; 013import ezvcard.util.ListMultimap; 014import ezvcard.util.StringUtils; 015 016/* 017 Copyright (c) 2012-2023, Michael Angstadt 018 All rights reserved. 019 020 Redistribution and use in source and binary forms, with or without 021 modification, are permitted provided that the following conditions are met: 022 023 1. Redistributions of source code must retain the above copyright notice, this 024 list of conditions and the following disclaimer. 025 2. Redistributions in binary form must reproduce the above copyright notice, 026 this list of conditions and the following disclaimer in the documentation 027 and/or other materials provided with the distribution. 028 029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 030 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 031 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 032 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 033 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 034 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 035 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 036 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 037 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 038 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 039 */ 040 041/** 042 * <p> 043 * Holds the validation warnings of a vCard. 044 * </p> 045 * <p> 046 * <b>Examples:</b> 047 * </p> 048 * 049 * <pre class="brush:java"> 050 * //validate a vCard object according to the rules of a specific version 051 * ValidationWarnings warnings = vcard.validate(VCardVersion.V3_0); 052 * 053 * //print all warnings to a string: 054 * System.out.println(warnings.toString()); 055 * //sample output: 056 * //W01: A FormattedName property is required for vCard versions 3.0 and 4.0. 057 * //[Gender] | W02: Property is not supported in this vCard version. Supported versions are: [4.0] 058 * 059 * //iterate over the warnings 060 * for (Map.Entry<VCardProperty, List<Warning>> entry : warnings) { 061 * //the property that caused the warning(s) 062 * VCardProperty property = entry.getKey(); 063 * 064 * //the list of warnings that belong to this property 065 * List<Warning> propWarnings = entry.getValue(); 066 * 067 * if (property == null) { 068 * //it's a warning about the vCard as a whole 069 * } 070 * 071 * //each warning message has a numeric code 072 * //this allows you to programmatically respond to specific warning messages 073 * List<Warning> propWarnings = entry.getValue(); 074 * for (Warning w : propWarnings) { 075 * System.out.println("Code: " + w.getCode()); 076 * System.out.printkn("Message: " + w.getMessage()); 077 * } 078 * } 079 * 080 * //you can also get the warnings of specific property classes 081 * List<Warnings> telWarnings = warnings.getByProperty(Telephone.class); 082 * </pre> 083 * 084 * @author Michael Angstadt 085 * @see VCard#validate 086 */ 087public class ValidationWarnings implements Iterable<Map.Entry<VCardProperty, List<ValidationWarning>>> { 088 private final ListMultimap<VCardProperty, ValidationWarning> warnings = new ListMultimap<>(new IdentityHashMap<>()); 089 090 /** 091 * Adds a validation warning. 092 * @param property the property that caused the warning 093 * @param warning the warning 094 */ 095 public void add(VCardProperty property, ValidationWarning warning) { 096 warnings.put(property, warning); 097 } 098 099 /** 100 * Adds a property's validation warnings. 101 * @param property the property that caused the warnings 102 * @param warnings the warnings 103 */ 104 public void add(VCardProperty property, List<ValidationWarning> warnings) { 105 this.warnings.putAll(property, warnings); 106 } 107 108 /** 109 * Gets all of the validation warnings. 110 * @return the validation warnings 111 */ 112 public ListMultimap<VCardProperty, ValidationWarning> getWarnings() { 113 return warnings; 114 } 115 116 /** 117 * Determines whether or not the warnings list is empty. 118 * @return true if there are no warnings, false if there is at least one 119 * warning 120 */ 121 public boolean isEmpty() { 122 return warnings.isEmpty(); 123 } 124 125 /** 126 * Gets all validation warnings that belong to a property of a specific 127 * class. 128 * @param propertyClass the property class (e.g. {@code Telephone.class}) or 129 * null to get the warnings that apply to the vCard as a whole 130 * @return the validation warnings 131 */ 132 public List<ValidationWarning> getByProperty(Class<? extends VCardProperty> propertyClass) { 133 List<ValidationWarning> propWarnings = new ArrayList<>(); 134 for (Map.Entry<VCardProperty, List<ValidationWarning>> entry : warnings) { 135 VCardProperty property = entry.getKey(); 136 137 if ((property == null && propertyClass == null) || (property != null && propertyClass == property.getClass())) { 138 List<ValidationWarning> propViolations = entry.getValue(); 139 propWarnings.addAll(propViolations); 140 } 141 } 142 return propWarnings; 143 } 144 145 /** 146 * <p> 147 * Outputs all validation warnings as a newline-delimited string. For 148 * example: 149 * </p> 150 * 151 * <pre> 152 * W01: A FormattedName property is required for vCard versions 3.0 and 4.0. 153 * [Gender] | W02: Property is not supported in this vCard version. Supported versions are: [4.0] 154 * </pre> 155 */ 156 @Override 157 public String toString() { 158 NumberFormat nf = NumberFormat.getIntegerInstance(Locale.ROOT); 159 nf.setMinimumIntegerDigits(2); 160 161 StringBuilder sb = new StringBuilder(); 162 for (Map.Entry<VCardProperty, List<ValidationWarning>> entry : warnings) { 163 VCardProperty property = entry.getKey(); 164 List<ValidationWarning> propViolations = entry.getValue(); 165 166 for (ValidationWarning propViolation : propViolations) { 167 if (property != null) { 168 sb.append('['); 169 sb.append(property.getClass().getSimpleName()); 170 sb.append("] | "); 171 } 172 173 Integer code = propViolation.getCode(); 174 if (code != null) { 175 sb.append('W'); 176 sb.append(nf.format(code)); 177 sb.append(": "); 178 } 179 180 sb.append(propViolation.getMessage()); 181 sb.append(StringUtils.NEWLINE); 182 } 183 } 184 185 return sb.toString(); 186 } 187 188 public Iterator<Entry<VCardProperty, List<ValidationWarning>>> iterator() { 189 return warnings.iterator(); 190 } 191}