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