001 package ezvcard.types;
002
003 import java.util.List;
004
005 import javax.xml.namespace.QName;
006
007 import org.w3c.dom.Element;
008
009 import ezvcard.VCard;
010 import ezvcard.VCardSubTypes;
011 import ezvcard.VCardVersion;
012 import ezvcard.io.CompatibilityMode;
013 import ezvcard.io.EmbeddedVCardException;
014 import ezvcard.io.SkipMeException;
015 import ezvcard.util.HCardElement;
016 import ezvcard.util.XCardElement;
017
018 /*
019 Copyright (c) 2012, Michael Angstadt
020 All rights reserved.
021
022 Redistribution and use in source and binary forms, with or without
023 modification, are permitted provided that the following conditions are met:
024
025 1. Redistributions of source code must retain the above copyright notice, this
026 list of conditions and the following disclaimer.
027 2. Redistributions in binary form must reproduce the above copyright notice,
028 this list of conditions and the following disclaimer in the documentation
029 and/or other materials provided with the distribution.
030
031 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
032 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
033 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
034 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
035 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
036 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
037 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
038 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
039 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
040 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
041
042 The views and conclusions contained in the software and documentation are those
043 of the authors and should not be interpreted as representing official policies,
044 either expressed or implied, of the FreeBSD Project.
045 */
046
047 /**
048 * Represents a vCard key/value pair entry (called a "type" or "property").
049 * @author Michael Angstadt
050 */
051 public abstract class VCardType implements Comparable<VCardType> {
052 /**
053 * The name of the type.
054 */
055 protected final String typeName;
056
057 /**
058 * The group that this type belongs to or null if it doesn't belong to a
059 * group.
060 */
061 protected String group;
062
063 /**
064 * The list of attributes that are associated with this type (called
065 * "sub types" or "parameters").
066 */
067 protected VCardSubTypes subTypes = new VCardSubTypes();
068
069 /**
070 * @param typeName the type name (e.g. "ADR")
071 */
072 public VCardType(String typeName) {
073 this.typeName = typeName;
074 }
075
076 /**
077 * Gets the name of this type.
078 * @return the type name (e.g. "ADR")
079 */
080 public String getTypeName() {
081 return typeName;
082 }
083
084 /**
085 * Gets the vCard versions that support this type.
086 * @return the vCard versions that support this type.
087 */
088 public VCardVersion[] getSupportedVersions() {
089 return VCardVersion.values();
090 }
091
092 /**
093 * Converts this type object to a string for sending over the wire. It is
094 * NOT responsible for folding.
095 * @param version the version vCard that is being generated
096 * @param warnings allows the programmer to alert the user to any
097 * note-worthy (but non-critical) issues that occurred during the
098 * marshalling process
099 * @param compatibilityMode allows the programmer to customize the
100 * marshalling process depending on the expected consumer of the vCard
101 * @return the string for sending over the wire
102 * @throws SkipMeException if this type should NOT be marshalled into the
103 * vCard
104 * @throws EmbeddedVCardException if the value of this type is an embedded
105 * vCard (i.e. the AGENT type)
106 */
107 public final String marshalText(VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
108 StringBuilder sb = new StringBuilder();
109 doMarshalText(sb, version, warnings, compatibilityMode);
110 return sb.toString();
111 }
112
113 /**
114 * Converts this type object to a string for sending over the wire. It is
115 * NOT responsible for folding.
116 * @param value the buffer to add the marshalled value to
117 * @param version the version vCard that is being generated
118 * @param warnings allows the programmer to alert the user to any
119 * note-worthy (but non-critical) issues that occurred during the
120 * marshalling process
121 * @param compatibilityMode allows the programmer to customize the
122 * marshalling process depending on the expected consumer of the vCard
123 * @throws SkipMeException if this type should NOT be marshalled into the
124 * vCard
125 * @throws EmbeddedVCardException if the value of this type is an embedded
126 * vCard (i.e. the AGENT type)
127 */
128 protected abstract void doMarshalText(StringBuilder value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode);
129
130 /**
131 * Marshals this type for inclusion in an xCard (XML document).
132 * @param parent the XML element that the type's value will be inserted
133 * into. For example, this would be the "<fn>" element for the "FN"
134 * type.
135 * @param version the version vCard that is being generated
136 * @param warnings allows the programmer to alert the user to any
137 * note-worthy (but non-critical) issues that occurred during the
138 * marshalling process
139 * @param compatibilityMode allows the programmer to customize the
140 * marshalling process depending on the expected consumer of the vCard
141 * @throws SkipMeException if this type should NOT be marshalled into the
142 * vCard
143 */
144 public final void marshalXml(Element parent, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
145 XCardElement wrapper = new XCardElement(parent, version);
146 doMarshalXml(wrapper, warnings, compatibilityMode);
147 }
148
149 /**
150 * Marshals this type for inclusion in an xCard (XML document). All child
151 * classes SHOULD override this, but are not required to.
152 * @param parent the XML element that the type's value will be inserted
153 * into. For example, this would be the "<fn>" element for the "FN"
154 * type.
155 * @param warnings allows the programmer to alert the user to any
156 * note-worthy (but non-critical) issues that occurred during the
157 * marshalling process
158 * @param compatibilityMode allows the programmer to customize the
159 * marshalling process depending on the expected consumer of the vCard
160 * @throws SkipMeException if this type should NOT be marshalled into the
161 * vCard
162 */
163 protected void doMarshalXml(XCardElement parent, List<String> warnings, CompatibilityMode compatibilityMode) {
164 String value = marshalText(parent.version(), warnings, compatibilityMode);
165 parent.append("unknown", value);
166 }
167
168 /**
169 * Gets the Sub Types to send over the wire.
170 * @param version the version vCard that is being generated
171 * @param warnings allows the programmer to alert the user to any
172 * note-worthy (but non-critical) issues that occurred during the
173 * marshalling process
174 * @param compatibilityMode allows the programmer to customize the
175 * marshalling process depending on the expected consumer of the vCard
176 * @param vcard the vCard that is being marshalled
177 * @return the sub types that will be sent
178 */
179 public final VCardSubTypes marshalSubTypes(VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode, VCard vcard) {
180 VCardSubTypes copy = new VCardSubTypes(subTypes);
181 doMarshalSubTypes(copy, version, warnings, compatibilityMode, vcard);
182 return copy;
183 }
184
185 /**
186 * Gets the sub types that will be sent over the wire.
187 *
188 * <p>
189 * If this method is NOT overridden, then the type's sub types will be sent
190 * over the wire as-is. In other words, whatever is in the
191 * {@link VCardType#subTypes} field will be sent. Child classes can override
192 * this method in order to modify the sub types before they are marshalled.
193 * </p>
194 * @param subTypes the sub types that will be marshalled into the vCard.
195 * This object is a copy of the {@link VCardType#subTypes} field, so any
196 * modifications done to this object will not effect the state of the field.
197 * @param version the version vCard that is being generated
198 * @param warnings allows the programmer to alert the user to any
199 * note-worthy (but non-critical) issues that occurred during the
200 * marshalling process
201 * @param compatibilityMode allows the programmer to customize the
202 * marshalling process depending on the expected consumer of the vCard
203 * @param vcard the {@link VCard} object that is being marshalled
204 */
205 protected void doMarshalSubTypes(VCardSubTypes subTypes, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode, VCard vcard) {
206 //do nothing
207 }
208
209 /**
210 * Unmarshals the type value from off the wire.
211 * @param subTypes the sub types that were parsed
212 * @param value the unfolded value from off the wire. If the wire value is
213 * in "quoted-printable" encoding, it will be decoded.
214 * @param version the version of the vCard that is being read or null if the
215 * VERSION type has not been parsed yet (v3.0 and v4.0 require that the
216 * VERSION type be at the top of the vCard, but v2.1 has no such
217 * requirement)
218 * @param warnings allows the programmer to alert the user to any
219 * note-worthy (but non-critical) issues that occurred during the
220 * unmarshalling process
221 * @param compatibilityMode allows the programmer to customize the
222 * unmarshalling process depending on where the vCard came from
223 * @throws SkipMeException if this type should NOT be added to the
224 * {@link VCard} object
225 * @throws EmbeddedVCardException if the value of this type is an embedded
226 * vCard (i.e. the AGENT type)
227 */
228 public final void unmarshalText(VCardSubTypes subTypes, String value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
229 this.subTypes = subTypes;
230 doUnmarshalText(value, version, warnings, compatibilityMode);
231 }
232
233 /**
234 * Unmarshals the type value from off the wire.
235 * @param value the unfolded value from off the wire. If the wire value is
236 * in the "quoted-printable" encoding, it will be decoded.
237 * @param version the version of the vCard that is being read or null if the
238 * VERSION type has not been parsed yet (v3.0 and v4.0 require that the
239 * VERSION type be at the top of the vCard, but v2.1 has no such
240 * requirement)
241 * @param warnings allows the programmer to alert the user to any
242 * note-worthy (but non-critical) issues that occurred during the
243 * unmarshalling process
244 * @param compatibilityMode allows you to customize the unmarshalling
245 * process depending on where the vCard came from
246 * @throws SkipMeException if this type should NOT be added to the
247 * {@link VCard} object
248 * @throws EmbeddedVCardException if the value of this type is an embedded
249 * vCard (i.e. the AGENT type)
250 */
251 protected abstract void doUnmarshalText(String value, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode);
252
253 /**
254 * Unmarshals the type from an xCard (XML document).
255 * @param subTypes the sub types that were parsed
256 * @param element the XML element that contains the type data. For example,
257 * this would be the "<fn>" element for the "FN" type. This object
258 * will NOT include the "<parameters>" child element (it is removed
259 * after being unmarshalled into a {@link VCardSubTypes} object).
260 * @param version the version of the xCard
261 * @param warnings allows the programmer to alert the user to any
262 * note-worthy (but non-critical) issues that occurred during the
263 * unmarshalling process
264 * @param compatibilityMode allows the programmer to customize the
265 * unmarshalling process depending on where the vCard came from
266 * @throws SkipMeException if this type should NOT be added to the
267 * {@link VCard} object
268 * @throws UnsupportedOperationException if the type class does not support
269 * xCard parsing
270 */
271 public final void unmarshalXml(VCardSubTypes subTypes, Element element, VCardVersion version, List<String> warnings, CompatibilityMode compatibilityMode) {
272 this.subTypes = subTypes;
273 XCardElement wrapper = new XCardElement(element, version);
274 doUnmarshalXml(wrapper, warnings, compatibilityMode);
275 }
276
277 /**
278 * Unmarshals the type from an xCard (XML document).
279 * @param element the XML element that contains the type data. For example,
280 * this would be the "<fn>" element for the "FN" type. This object
281 * will NOT include the "<parameters>" child element (it is removed
282 * after being unmarshalled into a {@link VCardSubTypes} object).
283 * @param warnings allows the programmer to alert the user to any
284 * note-worthy (but non-critical) issues that occurred during the
285 * unmarshalling process
286 * @param compatibilityMode allows the programmer to customize the
287 * unmarshalling process depending on where the vCard came from
288 * @throws SkipMeException if this type should NOT be added to the
289 * {@link VCard} object
290 * @throws UnsupportedOperationException if the type class does not support
291 * xCard parsing
292 */
293 protected void doUnmarshalXml(XCardElement element, List<String> warnings, CompatibilityMode compatibilityMode) {
294 throw new UnsupportedOperationException("This type class does not support the parsing of xCards.");
295 }
296
297 /**
298 * Unmarshals the type from an hCard (HTML document).
299 * @param element the HTML element that contains the type data.
300 * @param warnings allows the programmer to alert the user to any
301 * note-worthy (but non-critical) issues that occurred during the
302 * unmarshalling process
303 * @throws SkipMeException if this type should NOT be added to the
304 * {@link VCard} object
305 * @throws EmbeddedVCardException if the value of this type is an embedded
306 * vCard (i.e. the AGENT type)
307 * @throws UnsupportedOperationException if the type class does not support
308 * hCard parsing
309 */
310 public final void unmarshalHtml(org.jsoup.nodes.Element element, List<String> warnings) {
311 HCardElement hcardElement = new HCardElement(element);
312 doUnmarshalHtml(hcardElement, warnings);
313 }
314
315 /**
316 * Unmarshals the type from an hCard (HTML document).
317 * @param element the HTML element that contains the type data.
318 * @param warnings allows the programmer to alert the user to any
319 * note-worthy (but non-critical) issues that occurred during the
320 * unmarshalling process
321 * @throws SkipMeException if this type should NOT be added to the
322 * {@link VCard} object
323 * @throws EmbeddedVCardException if the value of this type is an embedded
324 * vCard (i.e. the AGENT type)
325 */
326 protected void doUnmarshalHtml(HCardElement element, List<String> warnings) {
327 String value = element.value();
328 doUnmarshalText(value, VCardVersion.V3_0, warnings, CompatibilityMode.RFC);
329 }
330
331 /**
332 * <p>
333 * Gets the qualified name (XML namespace and local part) for marshalling
334 * the type to an XML document (xCard).
335 * </p>
336 * <p>
337 * Extended type classes should override this method. By default, this
338 * method returns <code>null</code>, which instructs the marshallers to
339 * assign the following qualified name to the type:<br>
340 * <br>
341 * Namespace: xCard namespace<br>
342 * Local part: a lower-cased version of the type name
343 * </p>
344 * @return the XML qualified name or null to use the default qualified name
345 */
346 public QName getQName() {
347 return null;
348 }
349
350 /**
351 * Gets all sub types (a.k.a "parameters") associated with this type. This
352 * method can be used to retrieve any extended, standard, or non-standard
353 * sub type.
354 *
355 * <p>
356 * Ideally, this method should NOT be used to retrieve the values of
357 * standard sub types because the type class should contain getter/setter
358 * methods for each standard sub type. For example, instead of calling
359 * <code>NoteType.getSubTypes().getLanguage()</code> to retrieve the
360 * "LANGUAGE" sub type of a NOTE, the {@link NoteType#getLanguage()} method
361 * should be called instead.
362 * </p>
363 * @return the type's sub types
364 */
365 public VCardSubTypes getSubTypes() {
366 return subTypes;
367 }
368
369 /**
370 * Gets this type's group.
371 * @return the group or null if it does not belong to a group
372 */
373 public String getGroup() {
374 return group;
375 }
376
377 /**
378 * Sets this type's group.
379 * @param group the group or null to remove the type's group
380 */
381 public void setGroup(String group) {
382 //TODO test for valid chars
383 // if (group != null && !group.matches("(?i)[-a-z0-9]+")) {
384 // throw new IllegalArgumentException("");
385 // }
386 this.group = group;
387 }
388
389 /**
390 * Sorts by PREF parameter ascending. Types that do not have a PREF
391 * parameter are pushed to the end of the list.
392 */
393 public int compareTo(VCardType that) {
394 Integer pref0 = this.getSubTypes().getPref();
395 Integer pref1 = that.getSubTypes().getPref();
396 if (pref0 == null && pref1 == null) {
397 return 0;
398 }
399 if (pref0 == null) {
400 return 1;
401 }
402 if (pref1 == null) {
403 return -1;
404 }
405 return pref1.compareTo(pref0);
406 }
407 }