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