2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.model
.agent
;
12 import java
.io
.Serializable
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Collection
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
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
;
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
;
40 import eu
.etaxonomy
.cdm
.model
.location
.Country
;
41 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
42 import eu
.etaxonomy
.cdm
.strategy
.merge
.MergeException
;
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.
49 * This class corresponds to: <ul>
50 * <li> ContactDetails according to the TDWG ontology
51 * <li> Contact (partially) according to the ABCD schema
56 * @since 08-Nov-2007 13:06:18
58 @XmlAccessorType(XmlAccessType
.FIELD
)
59 @XmlType(name
= "Contact", propOrder
= {
66 @XmlRootElement(name
= "Contact")
69 public class Contact
implements Serializable
, Cloneable
{
70 private static final long serialVersionUID
= -1851305307069277625L;
71 private static final Logger logger
= Logger
.getLogger(Contact
.class);
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
<>();
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
<>();
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
<>();
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
<>();
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
<>();
106 public static Contact
NewInstance() {
107 return new Contact();
111 * Creates a new contact
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
);
135 result
.addEmailAddress(email
);
137 if (faxNumber
!= null){
138 result
.addFaxNumber(faxNumber
);
140 if (phoneNumber
!= null){
141 result
.addPhoneNumber(phoneNumber
);
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
;
156 if (emailAddresses
!= null){
157 result
.emailAddresses
= emailAddresses
;
159 if (faxNumbers
!= null){
160 result
.faxNumbers
= faxNumbers
;
162 if (phoneNumbers
!= null){
163 result
.phoneNumbers
= phoneNumbers
;
166 for (URI uri
: urls
){
167 result
.urls
.add(uri
.toString());
173 // ************************ CONSTRUCTOR **************************/
180 // ************************ MERGE /MATCH ***************************/
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()){
190 if (this.addresses
== null){
191 this.addresses
= new HashSet
<>();
193 this.addresses
.add((Address
)address
.clone());
194 } catch (CloneNotSupportedException e
) {
195 throw new MergeException("Address must implement Cloneable");
201 private void mergeList(List list1
, List list2
){
202 for (Object obj2
: list2
){
203 if (! list1
.contains(obj2
)){
210 * True, if no contact data exists in any of the lists (email, phone, ...).
213 public boolean isEmpty(){
214 if (isEmpty(emailAddresses
) && isEmpty(faxNumbers
) && isEmpty(phoneNumbers
)
215 && isEmpty(urls
) && isEmpty(addresses
)){
222 private boolean isEmpty(Collection
<?
extends Object
> collection
) {
223 return collection
== null || collection
.isEmpty();
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.
231 * @return the set of postal addresses
234 public Set
<Address
> getAddresses(){
235 return this.addresses
;
239 * Adds a new postal {@link Address address} to the set of postal addresses of <i>this</i> contact.
241 * @param address the address to be added
242 * @see #getAddresses()
245 public void addAddress(Address address
){
246 if (address
!= null){
247 getAddresses().add(address
);
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
);
259 * Removes one element from the set of postal addresses of <i>this</i> contact.
261 * @param address the postal address of <i>this</i> contact which should be deleted
262 * @see #getAddresses()
264 public void removeAddress(Address address
){
265 getAddresses().remove(address
);
270 * Returns the List of strings representing the electronic mail addresses
271 * included in <i>this</i> contact.
273 public List
<String
> getEmailAddresses(){
274 if(this.emailAddresses
== null) {
275 this.emailAddresses
= new ArrayList
<>();
277 return this.emailAddresses
;
281 * @see #getEmailAddress()
283 public void addEmailAddress(String emailAddress
){
284 getEmailAddresses().add(emailAddress
);
288 * Removes one element from the list of email addresses of <i>this</i> contact.
290 * @param emailAddress the email address of <i>this</i> contact which should be deleted
291 * @see #getEmailAddresses()
293 public void removeEmailAddress(String emailAddress
){
294 getEmailAddresses().remove(emailAddress
);
298 // * Returns the list of {@link URI URIs} representing this contact
299 // * included in <i>this</i> contact.
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));
313 * Returns the list of {@link URI URIs} representing this contact
314 * included in <i>this</i> contact.
316 public List
<String
> getUrls(){
323 public void addUrl(URI url
){
324 this.urls
.add(url
.toString());
328 * Removes one element from the list of urls of <i>this</i> contact.
330 * @param url the url of <i>this</i> contact which should be deleted
333 public void removeUrl(URI url
){
334 this.urls
.remove(url
.toString());
339 * Returns the list of strings representing the phone numbers
340 * included in <i>this</i> contact.
342 public List
<String
> getPhoneNumbers(){
343 if(this.phoneNumbers
== null) {
344 this.phoneNumbers
= new ArrayList
<>();
346 return this.phoneNumbers
;
352 public void addPhoneNumber(String phoneNumber
){
353 getPhoneNumbers().add(phoneNumber
);
357 * Removes one element from the list of phone numbers of <i>this</i> contact.
359 * @param phoneNumber the phone number of <i>this</i> contact which should be deleted
360 * @see #getPhoneNumber()
362 public void removePhoneNumber(String phoneNumber
){
363 getPhoneNumbers().remove(phoneNumber
);
367 * Returns the list of strings representing the telefax numbers
368 * included in <i>this</i> contact.
370 public List
<String
> getFaxNumbers(){
371 if(this.faxNumbers
== null) {
372 this.faxNumbers
= new ArrayList
<>();
374 return this.faxNumbers
;
378 * @see #getFaxNumbers()
380 public void addFaxNumber(String faxNumber
){
381 getFaxNumbers().add(faxNumber
);
385 * Removes one element from the list of telefax numbers of <i>this</i> contact.
387 * @param faxNumber the telefax number of <i>this</i> contact which should be deleted
388 * @see #getFaxNumber()
390 public void removeFaxNumber(String faxNumber
){
391 getFaxNumbers().remove(faxNumber
);
394 //*********************** CLONE ********************************************************/
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.
401 * @see java.lang.Object#clone()
404 public Object
clone() {
406 Contact result
= (Contact
) super.clone();
407 result
.addresses
= new HashSet
<>();
408 for (Address adr
: this.addresses
){
409 result
.addAddress((Address
)adr
.clone());
411 //no changes to emailAdresses, faxnumbers, phonenumbers, urls
413 }catch (CloneNotSupportedException e
){
414 logger
.warn("Object does not implement cloneable");