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 }