001    package ezvcard.property;
002    
003    import java.util.ArrayList;
004    import java.util.Arrays;
005    import java.util.EnumSet;
006    import java.util.List;
007    import java.util.Set;
008    
009    import ezvcard.VCard;
010    import ezvcard.VCardVersion;
011    import ezvcard.Warning;
012    import ezvcard.parameter.VCardParameters;
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     The views and conclusions contained in the software and documentation are those
039     of the authors and should not be interpreted as representing official policies, 
040     either expressed or implied, of the FreeBSD Project.
041     */
042    
043    /**
044     * Represents a vCard key/value pair entry (called a "type" or "property").
045     * @author Michael Angstadt
046     */
047    public abstract class VCardProperty implements Comparable<VCardProperty> {
048            /**
049             * The group that this property belongs to or null if it doesn't belong to a
050             * group.
051             */
052            protected String group;
053    
054            /**
055             * The property's parameters.
056             */
057            protected VCardParameters parameters = new VCardParameters();
058    
059            /**
060             * Gets the vCard versions that support this property.
061             * @return the vCard versions that support this property.
062             */
063            public final Set<VCardVersion> getSupportedVersions() {
064                    return _supportedVersions();
065            }
066    
067            /**
068             * <p>
069             * Gets the vCard versions that support this property.
070             * </p>
071             * <p>
072             * This method should be overridden by child classes if the property does
073             * not support all vCard versions. The default implementation of this method
074             * returns all vCard versions.
075             * </p>
076             * @return the vCard versions that support this property.
077             */
078            protected Set<VCardVersion> _supportedVersions() {
079                    return EnumSet.copyOf(Arrays.asList(VCardVersion.values()));
080            }
081    
082            /**
083             * Checks the property for data consistency problems or deviations from the
084             * spec. These problems will not prevent the property from being written to
085             * a data stream, but may prevent it from being parsed correctly by the
086             * consuming application. These problems can largely be avoided by reading
087             * the Javadocs of the property class, or by being familiar with the vCard
088             * standard.
089             * @param version the version to check the property against (use 4.0 for
090             * xCard and jCard)
091             * @param vcard the vCard this property belongs to
092             * @see VCard#validate
093             * @return a list of warnings or an empty list if no problems were found
094             */
095            public final List<Warning> validate(VCardVersion version, VCard vcard) {
096                    List<Warning> warnings = new ArrayList<Warning>(0);
097    
098                    //check the supported versions
099                    Set<VCardVersion> supportedVersions = getSupportedVersions();
100                    if (!supportedVersions.contains(version)) {
101                            warnings.add(new Warning(2, supportedVersions));
102                    }
103    
104                    //check parameters
105                    warnings.addAll(parameters.validate(version));
106    
107                    _validate(warnings, version, vcard);
108    
109                    return warnings;
110            }
111    
112            /**
113             * Checks the property for data consistency problems or deviations from the
114             * spec. Meant to be overridden by child classes that wish to provide
115             * validation logic.
116             * @param warnings the list to add the warnings to
117             * @param version the version to check the property against
118             * @param vcard the vCard this property belongs to
119             */
120            protected void _validate(List<Warning> warnings, VCardVersion version, VCard vcard) {
121                    //empty
122            }
123    
124            /**
125             * Gets all of the property's parameters.
126             * @return the property's parameters
127             */
128            public VCardParameters getParameters() {
129                    return parameters;
130            }
131    
132            /**
133             * Sets the property's parameters.
134             * @param parameters the parameters
135             */
136            public void setParameters(VCardParameters parameters) {
137                    this.parameters = parameters;
138            }
139    
140            /**
141             * Gets the first value of a parameter.
142             * @param name the parameter name (case insensitive, e.g. "LANGUAGE")
143             * @return the parameter value or null if not found
144             */
145            public String getParameter(String name) {
146                    return parameters.first(name);
147            }
148    
149            /**
150             * Gets all values of a parameter.
151             * @param name the parameter name (case insensitive, e.g. "LANGUAGE")
152             * @return the parameter values
153             */
154            public List<String> getParameters(String name) {
155                    return parameters.get(name);
156            }
157    
158            /**
159             * Replaces all existing values of a parameter with the given value.
160             * @param name the parameter name (case insensitive, e.g. "LANGUAGE")
161             * @param value the parameter value
162             */
163            public void setParameter(String name, String value) {
164                    parameters.replace(name, value);
165            }
166    
167            /**
168             * Adds a value to a parameter.
169             * @param name the parameter name (case insensitive, e.g. "LANGUAGE")
170             * @param value the parameter value
171             */
172            public void addParameter(String name, String value) {
173                    parameters.put(name, value);
174            }
175    
176            /**
177             * Removes a parameter from the property.
178             * @param name the parameter name (case insensitive, e.g. "LANGUAGE")
179             */
180            public void removeParameter(String name) {
181                    parameters.removeAll(name);
182            }
183    
184            /**
185             * Gets this property's group.
186             * @return the group or null if it does not belong to a group
187             */
188            public String getGroup() {
189                    return group;
190            }
191    
192            /**
193             * Sets this property's group.
194             * @param group the group or null to remove the property's group
195             */
196            public void setGroup(String group) {
197                    this.group = group;
198            }
199    
200            /**
201             * Sorts by PREF parameter ascending. Properties that do not have a PREF
202             * parameter are pushed to the end of the list.
203             */
204            public int compareTo(VCardProperty that) {
205                    Integer pref0 = this.getParameters().getPref();
206                    Integer pref1 = that.getParameters().getPref();
207                    if (pref0 == null && pref1 == null) {
208                            return 0;
209                    }
210                    if (pref0 == null) {
211                            return 1;
212                    }
213                    if (pref1 == null) {
214                            return -1;
215                    }
216                    return pref1.compareTo(pref0);
217            }
218    
219            //Note: The following parameter helper methods are package-scoped to prevent them from cluttering up the Javadocs
220    
221            /**
222             * <p>
223             * Gets all PID values.
224             * </p>
225             * <p>
226             * <b>Supported versions:</b> {@code 4.0}
227             * </p>
228             * @return the PID values or empty set if there are none
229             * @see VCardParameters#getPids
230             */
231            List<Integer[]> getPids() {
232                    return parameters.getPids();
233            }
234    
235            /**
236             * <p>
237             * Adds a PID value.
238             * </p>
239             * <p>
240             * <b>Supported versions:</b> {@code 4.0}
241             * </p>
242             * @param localId the local ID
243             * @param clientPidMapRef the ID used to reference the property's globally
244             * unique identifier in the CLIENTPIDMAP property.
245             * @see VCardParameters#addPid(int, int)
246             */
247            void addPid(int localId, int clientPidMapRef) {
248                    parameters.addPid(localId, clientPidMapRef);
249            }
250    
251            /**
252             * <p>
253             * Removes all PID values.
254             * </p>
255             * <p>
256             * <b>Supported versions:</b> {@code 4.0}
257             * </p>
258             * @see VCardParameters#removePids
259             */
260            void removePids() {
261                    parameters.removePids();
262            }
263    
264            /**
265             * <p>
266             * Gets the preference value. The lower the number, the more preferred this
267             * property instance is compared with other properties in the same vCard of
268             * the same type. If a property doesn't have a preference value, then it is
269             * considered the least preferred.
270             * </p>
271             * <p>
272             * <b>Supported versions:</b> {@code 4.0}
273             * </p>
274             * @return the preference value or null if it doesn't exist
275             * @see VCardParameters#getPref
276             */
277            Integer getPref() {
278                    return parameters.getPref();
279            }
280    
281            /**
282             * <p>
283             * Sets the preference value. The lower the number, the more preferred this
284             * property instance is compared with other properties in the same vCard of
285             * the same type. If a property doesn't have a preference value, then it is
286             * considered the least preferred.
287             * </p>
288             * <p>
289             * <b>Supported versions:</b> {@code 4.0}
290             * </p>
291             * @param pref the preference value or null to remove
292             * @see VCardParameters#setPref
293             */
294            void setPref(Integer pref) {
295                    parameters.setPref(pref);
296            }
297    
298            /**
299             * Gets the language that the property value is written in.
300             * @return the language or null if not set
301             * @see VCardParameters#getLanguage
302             */
303            String getLanguage() {
304                    return parameters.getLanguage();
305            }
306    
307            /**
308             * Sets the language that the property value is written in.
309             * @param language the language or null to remove
310             * @see VCardParameters#setLanguage
311             */
312            void setLanguage(String language) {
313                    parameters.setLanguage(language);
314            }
315    
316            /**
317             * Gets the sorted position of this property when it is grouped together
318             * with other properties of the same type. Properties with low index values
319             * are put at the beginning of the sorted list and properties with high
320             * index values are put at the end of the list.
321             * @return the index or null if not set
322             * @see VCardParameters#setIndex
323             */
324            Integer getIndex() {
325                    return parameters.getIndex();
326            }
327    
328            /**
329             * Sets the sorted position of this property when it is grouped together
330             * with other properties of the same type. Properties with low index values
331             * are put at the beginning of the sorted list and properties with high
332             * index values are put at the end of the list.
333             * @param index the index or null to remove
334             * @see VCardParameters#setIndex
335             */
336            void setIndex(Integer index) {
337                    parameters.setIndex(index);
338            }
339    }