001package ezvcard.property; 002 003import java.util.ArrayList; 004import java.util.LinkedHashMap; 005import java.util.List; 006import java.util.Map; 007 008import ezvcard.VCard; 009import ezvcard.VCardVersion; 010import ezvcard.ValidationWarning; 011 012/* 013 Copyright (c) 2012-2023, Michael Angstadt 014 All rights reserved. 015 016 Redistribution and use in source and binary forms, with or without 017 modification, are permitted provided that the following conditions are met: 018 019 1. Redistributions of source code must retain the above copyright notice, this 020 list of conditions and the following disclaimer. 021 2. Redistributions in binary form must reproduce the above copyright notice, 022 this list of conditions and the following disclaimer in the documentation 023 and/or other materials provided with the distribution. 024 025 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 026 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 027 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 028 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 029 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 030 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 031 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 032 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 033 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 034 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 035 036 The views and conclusions contained in the software and documentation are those 037 of the authors and should not be interpreted as representing official policies, 038 either expressed or implied, of the FreeBSD Project. 039 */ 040 041/** 042 * <p> 043 * Defines the individual components of the person's name. 044 * </p> 045 * 046 * <p> 047 * <b>Code sample</b> 048 * </p> 049 * 050 * <pre class="brush:java"> 051 * VCard vcard = new VCard(); 052 * 053 * StructuredName n = new StructuredName(); 054 * n.setFamily("House"); 055 * n.setGiven("Gregory"); 056 * n.getPrefixes().add("Dr"); 057 * n.getSuffixes().add("MD"); 058 * vcard.setStructuredName(n); 059 * </pre> 060 * 061 * <p> 062 * <b>Property name:</b> {@code N} 063 * </p> 064 * <p> 065 * <b>Supported versions:</b> {@code 2.1, 3.0, 4.0} 066 * </p> 067 * @author Michael Angstadt 068 * @see <a href="http://tools.ietf.org/html/rfc6350#page-29">RFC 6350 p.29</a> 069 * @see <a href="http://tools.ietf.org/html/rfc2426#page-9">RFC 2426 p.9</a> 070 * @see <a href="http://www.imc.org/pdi/vcard-21.doc">vCard 2.1 p.9</a> 071 */ 072public class StructuredName extends VCardProperty implements HasAltId { 073 private String family; 074 private String given; 075 private final List<String> additional; 076 private final List<String> prefixes; 077 private final List<String> suffixes; 078 079 public StructuredName() { 080 additional = new ArrayList<>(); 081 prefixes = new ArrayList<>(); 082 suffixes = new ArrayList<>(); 083 } 084 085 /** 086 * Copy constructor. 087 * @param original the property to make a copy of 088 */ 089 public StructuredName(StructuredName original) { 090 super(original); 091 family = original.family; 092 given = original.given; 093 additional = new ArrayList<>(original.additional); 094 prefixes = new ArrayList<>(original.prefixes); 095 suffixes = new ArrayList<>(original.suffixes); 096 } 097 098 /** 099 * Gets the family name (aka "surname" or "last name"). 100 * @return the family name or null if not set 101 */ 102 public String getFamily() { 103 return family; 104 } 105 106 /** 107 * Sets the family name (aka "surname" or "last name"). 108 * @param family the family name or null to remove 109 */ 110 public void setFamily(String family) { 111 this.family = family; 112 } 113 114 /** 115 * Gets the given name (aka "first name"). 116 * @return the given name or null if not set 117 */ 118 public String getGiven() { 119 return given; 120 } 121 122 /** 123 * Sets the given name (aka "first name"). 124 * @param given the given name or null to remove 125 */ 126 public void setGiven(String given) { 127 this.given = given; 128 } 129 130 /** 131 * Gets the list that stores additional names the person goes by (for 132 * example, a middle name). 133 * @return the additional names (this list is mutable) 134 */ 135 public List<String> getAdditionalNames() { 136 return additional; 137 } 138 139 /** 140 * Gets the list that stores the person's honorific prefixes. 141 * @return the prefixes (e.g. "Dr.", "Mr.") (this list is mutable) 142 */ 143 public List<String> getPrefixes() { 144 return prefixes; 145 } 146 147 /** 148 * Gets the list that stores the person's honorary suffixes. 149 * @return the suffixes (e.g. "M.D.", "Jr.") (this list is mutable) 150 */ 151 public List<String> getSuffixes() { 152 return suffixes; 153 } 154 155 /** 156 * <p> 157 * Gets the list that holds string(s) which define how to sort the vCard. 158 * </p> 159 * <p> 160 * 2.1 and 3.0 vCards should use the {@link SortString} property instead. 161 * </p> 162 * <p> 163 * <b>Supported versions:</b> {@code 4.0} 164 * </p> 165 * @return the sort string(s) (this list is mutable). For example, if the 166 * family name is "d'Aboville" and the given name is "Christine", the sort 167 * strings might be ["Aboville", "Christine"]. 168 */ 169 public List<String> getSortAs() { 170 return parameters.getSortAs(); 171 } 172 173 /** 174 * <p> 175 * Defines a sortable version of the person's name. 176 * </p> 177 * <p> 178 * 2.1 and 3.0 vCards should use the {@link SortString} property instead. 179 * </p> 180 * <p> 181 * <b>Supported versions:</b> {@code 4.0} 182 * </p> 183 * @param family the sortable version of the family name (for example, 184 * "Adboville" if the family name is "d'Aboville") or null to remove 185 */ 186 public void setSortAs(String family) { 187 parameters.setSortAs(family); 188 } 189 190 /** 191 * <p> 192 * Defines a sortable version of the person's name. 193 * </p> 194 * <p> 195 * 2.1 and 3.0 vCards should use the {@link SortString} property instead. 196 * </p> 197 * <p> 198 * <b>Supported versions:</b> {@code 4.0} 199 * </p> 200 * @param family the sortable version of the family name (for example, 201 * "Adboville" if the family name is "d'Aboville") 202 * @param given the sortable version of the given name 203 */ 204 public void setSortAs(String family, String given) { 205 parameters.setSortAs(family, given); 206 } 207 208 @Override 209 public String getLanguage() { 210 return super.getLanguage(); 211 } 212 213 @Override 214 public void setLanguage(String language) { 215 super.setLanguage(language); 216 } 217 218 //@Override 219 public String getAltId() { 220 return parameters.getAltId(); 221 } 222 223 //@Override 224 public void setAltId(String altId) { 225 parameters.setAltId(altId); 226 } 227 228 @Override 229 protected Map<String, Object> toStringValues() { 230 Map<String, Object> values = new LinkedHashMap<>(); 231 values.put("family", family); 232 values.put("given", given); 233 values.put("additional", additional); 234 values.put("prefixes", prefixes); 235 values.put("suffixes", suffixes); 236 return values; 237 } 238 239 @Override 240 protected void _validate(List<ValidationWarning> warnings, VCardVersion version, VCard vcard) { 241 /* 242 * 2.1 does not allow multi-valued components. 243 */ 244 if (version == VCardVersion.V2_1) { 245 //@formatter:off 246 if (additional.size() > 1 || 247 prefixes.size() > 1 || 248 suffixes.size() > 1) { 249 warnings.add(new ValidationWarning(34)); 250 } 251 //@formatter:on 252 } 253 } 254 255 @Override 256 public StructuredName copy() { 257 return new StructuredName(this); 258 } 259 260 @Override 261 public int hashCode() { 262 final int prime = 31; 263 int result = super.hashCode(); 264 result = prime * result + additional.hashCode(); 265 result = prime * result + ((family == null) ? 0 : family.hashCode()); 266 result = prime * result + ((given == null) ? 0 : given.hashCode()); 267 result = prime * result + prefixes.hashCode(); 268 result = prime * result + suffixes.hashCode(); 269 return result; 270 } 271 272 @Override 273 public boolean equals(Object obj) { 274 if (this == obj) return true; 275 if (!super.equals(obj)) return false; 276 StructuredName other = (StructuredName) obj; 277 if (!additional.equals(other.additional)) return false; 278 if (family == null) { 279 if (other.family != null) return false; 280 } else if (!family.equals(other.family)) return false; 281 if (given == null) { 282 if (other.given != null) return false; 283 } else if (!given.equals(other.given)) return false; 284 if (!prefixes.equals(other.prefixes)) return false; 285 if (!suffixes.equals(other.suffixes)) return false; 286 return true; 287 } 288}