cleanup
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / agent / Contact.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.model.agent;
11
12 import java.io.Serializable;
13 import java.net.URI;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Set;
19
20 import javax.persistence.Column;
21 import javax.persistence.ElementCollection;
22 import javax.persistence.Embeddable;
23 import javax.persistence.FetchType;
24 import javax.persistence.OneToMany;
25 import javax.persistence.Transient;
26 import javax.xml.bind.annotation.XmlAccessType;
27 import javax.xml.bind.annotation.XmlAccessorType;
28 import javax.xml.bind.annotation.XmlElement;
29 import javax.xml.bind.annotation.XmlElementWrapper;
30 import javax.xml.bind.annotation.XmlRootElement;
31 import javax.xml.bind.annotation.XmlSchemaType;
32 import javax.xml.bind.annotation.XmlType;
33
34 import org.apache.commons.lang3.StringUtils;
35 import org.apache.log4j.Logger;
36 import org.hibernate.annotations.Cascade;
37 import org.hibernate.annotations.CascadeType;
38 import org.hibernate.envers.Audited;
39
40 import eu.etaxonomy.cdm.model.location.Country;
41 import eu.etaxonomy.cdm.model.location.Point;
42 import eu.etaxonomy.cdm.strategy.merge.MergeException;
43
44 /**
45 * The class for information on how to approach a {@link Person person} or an {@link Institution institution}.
46 * It includes telecommunication data and an electronic as well as
47 * multiple postal addresses.
48 * <P>
49 * This class corresponds to: <ul>
50 * <li> ContactDetails according to the TDWG ontology
51 * <li> Contact (partially) according to the ABCD schema
52 * </ul>
53 *
54 * @author m.doering
55 * @version 1.0
56 * @since 08-Nov-2007 13:06:18
57 */
58 @XmlAccessorType(XmlAccessType.FIELD)
59 @XmlType(name = "Contact", propOrder = {
60 "emailAddresses",
61 "urls",
62 "phoneNumbers",
63 "faxNumbers",
64 "addresses"
65 })
66 @XmlRootElement(name = "Contact")
67 @Embeddable
68 @Audited
69 public class Contact implements Serializable, Cloneable {
70 private static final long serialVersionUID = -1851305307069277625L;
71 private static final Logger logger = Logger.getLogger(Contact.class);
72
73
74 @XmlElementWrapper(name = "EmailAddresses", nillable = true)
75 @XmlElement(name = "EmailAddress")
76 @ElementCollection(fetch = FetchType.LAZY)
77 @Column(name = "contact_emailaddresses_element")
78 private List<String> emailAddresses = new ArrayList<>();
79
80 @XmlElementWrapper(name = "URLs", nillable = true)
81 @XmlElement(name = "URL")
82 @XmlSchemaType(name = "anyURI")
83 @ElementCollection(fetch = FetchType.LAZY)
84 @Column(name = "contact_urls_element" /*, length=330 */) //length >255 does not work in InnoDB AUD tables for Key length of (REV, id, url) key
85 private final List<String> urls = new ArrayList<>();
86
87 @XmlElementWrapper(name = "PhoneNumbers", nillable = true)
88 @XmlElement(name = "PhoneNumber")
89 @ElementCollection(fetch = FetchType.LAZY)
90 @Column(name = "contact_phonenumbers_element")
91 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
92 private List<String> phoneNumbers = new ArrayList<>();
93
94 @XmlElementWrapper(name = "FaxNumbers", nillable = true)
95 @XmlElement(name = "FaxNumber")
96 @ElementCollection(fetch = FetchType.LAZY)
97 @Column(name = "contact_faxnumbers_element")
98 private List<String> faxNumbers = new ArrayList<>();
99
100 @XmlElementWrapper(name = "Addresses", nillable = true)
101 @XmlElement(name = "Address")
102 @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
103 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
104 protected Set<Address> addresses = new HashSet<>();
105
106 public static Contact NewInstance() {
107 return new Contact();
108 }
109
110 /**
111 * Creates a new contact
112 * @param street
113 * @param postcode
114 * @param locality
115 * @param country
116 * @param pobox
117 * @param region
118 * @param email
119 * @param faxNumber
120 * @param phoneNumber
121 * @param url
122 * @param location
123 * @return
124 */
125 public static Contact NewInstance(String street, String postcode, String locality,
126 Country country, String pobox, String region,
127 String email, String faxNumber, String phoneNumber, URI url, Point location) {
128 Contact result = new Contact();
129 if (country != null || StringUtils.isNotBlank(locality) || StringUtils.isNotBlank(pobox) || StringUtils.isNotBlank(postcode) ||
130 StringUtils.isNotBlank(region) || StringUtils.isNotBlank(street) ){
131 Address newAddress = Address.NewInstance(country, locality, pobox, postcode, region, street, location);
132 result.addAddress(newAddress);
133 }
134 if (email != null){
135 result.addEmailAddress(email);
136 }
137 if (faxNumber != null){
138 result.addFaxNumber(faxNumber);
139 }
140 if (phoneNumber != null){
141 result.addPhoneNumber(phoneNumber);
142 }
143 if (url != null){
144 result.addUrl(url);
145 }
146 return result;
147 }
148
149
150 public static Contact NewInstance(Set<Address> addresses, List<String> emailAddresses,
151 List<String> faxNumbers, List<String> phoneNumbers, List<URI> urls) {
152 Contact result = new Contact();
153 if (addresses != null){
154 result.addresses = addresses;
155 }
156 if (emailAddresses != null){
157 result.emailAddresses = emailAddresses;
158 }
159 if (faxNumbers != null){
160 result.faxNumbers = faxNumbers;
161 }
162 if (phoneNumbers != null){
163 result.phoneNumbers = phoneNumbers;
164 }
165 if (urls != null){
166 for (URI uri : urls){
167 result.urls.add(uri.toString());
168 }
169 }
170 return result;
171 }
172
173 // ************************ CONSTRUCTOR **************************/
174 /**
175 * Class constructor.
176 */
177 public Contact() {
178 }
179
180 // ************************ MERGE /MATCH ***************************/
181
182 public void merge(Contact contact2) throws MergeException{
183 if (contact2 != null){
184 mergeList(this.getEmailAddresses(), contact2.getEmailAddresses());
185 mergeList(this.getFaxNumbers(), contact2.getFaxNumbers());
186 mergeList(this.getPhoneNumbers(), contact2.getPhoneNumbers());
187 mergeList(this.getUrls(), contact2.getUrls());
188 for (Address address : contact2.getAddresses()){
189 try {
190 if (this.addresses == null){
191 this.addresses = new HashSet<>();
192 }
193 this.addresses.add(address.clone());
194 } catch (CloneNotSupportedException e) {
195 throw new MergeException("Address must implement Cloneable");
196 }
197 }
198 }
199 }
200
201 private void mergeList(List list1, List list2){
202 for (Object obj2 : list2){
203 if (! list1.contains(obj2)){
204 list1.add(obj2);
205 }
206 }
207 }
208
209 /**
210 * True, if no contact data exists in any of the lists (email, phone, ...).
211 */
212 @Transient
213 public boolean isEmpty(){
214 if (isEmpty(emailAddresses) && isEmpty(faxNumbers) && isEmpty(phoneNumbers)
215 && isEmpty(urls) && isEmpty(addresses)){
216 return true;
217 }else{
218 return false;
219 }
220 }
221
222 private boolean isEmpty(Collection<? extends Object> collection) {
223 return collection == null || collection.isEmpty();
224 }
225
226 /**
227 * Returns the set of postal {@link Address addresses} belonging to <i>this</i> contact.
228 * A {@link Person person} or an {@link Institution institution} cannot have more than one contact,
229 * but a contact may include several postal addresses.
230 *
231 * @return the set of postal addresses
232 * @see Address
233 */
234 public Set<Address> getAddresses(){
235 return this.addresses;
236 }
237
238 /**
239 * Adds a new postal {@link Address address} to the set of postal addresses of <i>this</i> contact.
240 *
241 * @param address the address to be added
242 * @see #getAddresses()
243 * @see Address
244 */
245 public void addAddress(Address address){
246 if (address != null){
247 getAddresses().add(address);
248 }
249 }
250
251 public Address addAddress(String street, String postcode, String locality,
252 Country country, String pobox, String region, Point location){
253 Address newAddress = Address.NewInstance(country, locality, pobox, postcode, region, street, location);
254 getAddresses().add(newAddress);
255 return newAddress;
256 }
257
258 /**
259 * Removes one element from the set of postal addresses of <i>this</i> contact.
260 *
261 * @param address the postal address of <i>this</i> contact which should be deleted
262 * @see #getAddresses()
263 */
264 public void removeAddress(Address address){
265 getAddresses().remove(address);
266 }
267
268
269 /**
270 * Returns the List of strings representing the electronic mail addresses
271 * included in <i>this</i> contact.
272 */
273 public List<String> getEmailAddresses(){
274 if(this.emailAddresses == null) {
275 this.emailAddresses = new ArrayList<>();
276 }
277 return this.emailAddresses;
278 }
279
280 /**
281 * @see #getEmailAddress()
282 */
283 public void addEmailAddress(String emailAddress){
284 getEmailAddresses().add(emailAddress);
285 }
286
287 /**
288 * Removes one element from the list of email addresses of <i>this</i> contact.
289 *
290 * @param emailAddress the email address of <i>this</i> contact which should be deleted
291 * @see #getEmailAddresses()
292 */
293 public void removeEmailAddress(String emailAddress){
294 getEmailAddresses().remove(emailAddress);
295 }
296
297 // /**
298 // * Returns the list of {@link URI URIs} representing this contact
299 // * included in <i>this</i> contact.
300 // */
301 // @Transient //TODO preliminary workaround as we get LazyInit Exception in JSON #4444
302 // public List<URI> getUrls(){
303 // List<URI> result = new ArrayList<URI>();
304 // if(this.urls != null) {
305 // for (String uri : this.urls){
306 // result.add(URI.create(uri));
307 // }
308 // }
309 // return result;
310 // }
311
312 /**
313 * Returns the list of {@link URI URIs} representing this contact
314 * included in <i>this</i> contact.
315 */
316 public List<String> getUrls(){
317 return this.urls;
318 }
319
320 /**
321 * @see #getUrls()
322 */
323 public void addUrl(URI url){
324 this.urls.add(url.toString());
325 }
326
327 /**
328 * Removes one element from the list of urls of <i>this</i> contact.
329 *
330 * @param url the url of <i>this</i> contact which should be deleted
331 * @see #getUrls()
332 */
333 public void removeUrl(URI url){
334 this.urls.remove(url.toString());
335 }
336
337
338 /**
339 * Returns the list of strings representing the phone numbers
340 * included in <i>this</i> contact.
341 */
342 public List<String> getPhoneNumbers(){
343 if(this.phoneNumbers == null) {
344 this.phoneNumbers = new ArrayList<>();
345 }
346 return this.phoneNumbers;
347 }
348
349 /**
350 * @see #getPhone()
351 */
352 public void addPhoneNumber(String phoneNumber){
353 getPhoneNumbers().add(phoneNumber);
354 }
355
356 /**
357 * Removes one element from the list of phone numbers of <i>this</i> contact.
358 *
359 * @param phoneNumber the phone number of <i>this</i> contact which should be deleted
360 * @see #getPhoneNumber()
361 */
362 public void removePhoneNumber(String phoneNumber){
363 getPhoneNumbers().remove(phoneNumber);
364 }
365
366 /**
367 * Returns the list of strings representing the telefax numbers
368 * included in <i>this</i> contact.
369 */
370 public List<String> getFaxNumbers(){
371 if(this.faxNumbers == null) {
372 this.faxNumbers = new ArrayList<>();
373 }
374 return this.faxNumbers;
375 }
376
377 /**
378 * @see #getFaxNumbers()
379 */
380 public void addFaxNumber(String faxNumber){
381 getFaxNumbers().add(faxNumber);
382 }
383
384 /**
385 * Removes one element from the list of telefax numbers of <i>this</i> contact.
386 *
387 * @param faxNumber the telefax number of <i>this</i> contact which should be deleted
388 * @see #getFaxNumber()
389 */
390 public void removeFaxNumber(String faxNumber){
391 getFaxNumbers().remove(faxNumber);
392 }
393
394 //*********************** CLONE ********************************************************/
395
396 /**
397 * Clones <i>this</i> Contact. This is a shortcut that enables to create
398 * a new instance that differs only slightly from <i>this</i> Contact.
399 *
400 *
401 * @see java.lang.Object#clone()
402 */
403 @Override
404 public Object clone() {
405 try{
406 Contact result = (Contact) super.clone();
407 result.addresses = new HashSet<>();
408 for (Address adr : this.addresses){
409 result.addAddress(adr.clone());
410 }
411 //no changes to emailAdresses, faxnumbers, phonenumbers, urls
412 return result;
413 }catch (CloneNotSupportedException e){
414 logger.warn("Object does not implement cloneable");
415 e.printStackTrace();
416 return null;
417 }
418 }
419 }