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.
9 package eu
.etaxonomy
.cdm
.model
.agent
;
11 import java
.io
.Serializable
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Collection
;
14 import java
.util
.HashSet
;
15 import java
.util
.List
;
18 import javax
.persistence
.Column
;
19 import javax
.persistence
.ElementCollection
;
20 import javax
.persistence
.Embeddable
;
21 import javax
.persistence
.FetchType
;
22 import javax
.persistence
.OneToMany
;
23 import javax
.persistence
.Transient
;
24 import javax
.xml
.bind
.annotation
.XmlAccessType
;
25 import javax
.xml
.bind
.annotation
.XmlAccessorType
;
26 import javax
.xml
.bind
.annotation
.XmlElement
;
27 import javax
.xml
.bind
.annotation
.XmlElementWrapper
;
28 import javax
.xml
.bind
.annotation
.XmlRootElement
;
29 import javax
.xml
.bind
.annotation
.XmlSchemaType
;
30 import javax
.xml
.bind
.annotation
.XmlType
;
32 import org
.apache
.commons
.lang3
.StringUtils
;
33 import org
.apache
.logging
.log4j
.LogManager
;
34 import org
.apache
.logging
.log4j
.Logger
;
35 import org
.hibernate
.annotations
.Cascade
;
36 import org
.hibernate
.annotations
.CascadeType
;
37 import org
.hibernate
.envers
.Audited
;
38 import org
.hibernate
.search
.annotations
.FieldBridge
;
40 import eu
.etaxonomy
.cdm
.common
.URI
;
41 import eu
.etaxonomy
.cdm
.hibernate
.search
.UriBridge
;
42 import eu
.etaxonomy
.cdm
.model
.location
.Country
;
43 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
44 import eu
.etaxonomy
.cdm
.strategy
.merge
.MergeException
;
47 * The class for information on how to approach a {@link Person person} or an {@link Institution institution}.
48 * It includes telecommunication data and an electronic as well as
49 * multiple postal addresses.
51 * This class corresponds to: <ul>
52 * <li> ContactDetails according to the TDWG ontology
53 * <li> Contact (partially) according to the ABCD schema
57 * @since 08-Nov-2007 13:06:18
59 @XmlAccessorType(XmlAccessType
.FIELD
)
60 @XmlType(name
= "Contact", propOrder
= {
67 @XmlRootElement(name
= "Contact")
70 public class Contact
implements Serializable
, Cloneable
{
72 private static final long serialVersionUID
= -1851305307069277625L;
73 private static final Logger logger
= LogManager
.getLogger();
76 @XmlElementWrapper(name
= "EmailAddresses", nillable
= true)
77 @XmlElement(name
= "EmailAddress")
78 @ElementCollection(fetch
= FetchType
.LAZY
)
79 @Column(name
= "contact_emailaddresses_element")
80 private List
<String
> emailAddresses
= new ArrayList
<>();
82 @XmlElementWrapper(name
= "URLs", nillable
= true)
83 @XmlElement(name
= "URL")
84 @XmlSchemaType(name
= "anyURI")
85 @FieldBridge(impl
= UriBridge
.class)
86 @ElementCollection(fetch
= FetchType
.LAZY
)
87 @Column(name
= "contact_urls_element" /*, length=330 */) //length >255 does not work in InnoDB AUD tables for Key length of (REV, id, url) key
88 private final List
<String
> urls
= new ArrayList
<>();
90 @XmlElementWrapper(name
= "PhoneNumbers", nillable
= true)
91 @XmlElement(name
= "PhoneNumber")
92 @ElementCollection(fetch
= FetchType
.LAZY
)
93 @Column(name
= "contact_phonenumbers_element")
94 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
, CascadeType
.DELETE
})
95 private List
<String
> phoneNumbers
= new ArrayList
<>();
97 @XmlElementWrapper(name
= "FaxNumbers", nillable
= true)
98 @XmlElement(name
= "FaxNumber")
99 @ElementCollection(fetch
= FetchType
.LAZY
)
100 @Column(name
= "contact_faxnumbers_element")
101 private List
<String
> faxNumbers
= new ArrayList
<>();
103 @XmlElementWrapper(name
= "Addresses", nillable
= true)
104 @XmlElement(name
= "Address")
105 @OneToMany(fetch
= FetchType
.LAZY
, orphanRemoval
=true)
106 @Cascade({CascadeType
.SAVE_UPDATE
, CascadeType
.MERGE
})
107 protected Set
<Address
> addresses
= new HashSet
<>();
109 public static Contact
NewInstance() {
110 return new Contact();
114 * Creates a new contact
128 public static Contact
NewInstance(String street
, String postcode
, String locality
,
129 Country country
, String pobox
, String region
,
130 String email
, String faxNumber
, String phoneNumber
, URI url
, Point location
) {
131 Contact result
= new Contact();
132 if (country
!= null || StringUtils
.isNotBlank(locality
) || StringUtils
.isNotBlank(pobox
) || StringUtils
.isNotBlank(postcode
) ||
133 StringUtils
.isNotBlank(region
) || StringUtils
.isNotBlank(street
) ){
134 Address newAddress
= Address
.NewInstance(country
, locality
, pobox
, postcode
, region
, street
, location
);
135 result
.addAddress(newAddress
);
138 result
.addEmailAddress(email
);
140 if (faxNumber
!= null){
141 result
.addFaxNumber(faxNumber
);
143 if (phoneNumber
!= null){
144 result
.addPhoneNumber(phoneNumber
);
153 public static Contact
NewInstance(Set
<Address
> addresses
, List
<String
> emailAddresses
,
154 List
<String
> faxNumbers
, List
<String
> phoneNumbers
, List
<URI
> urls
) {
155 Contact result
= new Contact();
156 if (addresses
!= null){
157 result
.addresses
= addresses
;
159 if (emailAddresses
!= null){
160 result
.emailAddresses
= emailAddresses
;
162 if (faxNumbers
!= null){
163 result
.faxNumbers
= faxNumbers
;
165 if (phoneNumbers
!= null){
166 result
.phoneNumbers
= phoneNumbers
;
169 for (URI uri
: urls
){
170 result
.urls
.add(uri
.toString());
176 // ************************ CONSTRUCTOR **************************/
183 // ************************ MERGE /MATCH ***************************/
185 public void merge(Contact contact2
) throws MergeException
{
186 if (contact2
!= null){
187 mergeList(this.getEmailAddresses(), contact2
.getEmailAddresses());
188 mergeList(this.getFaxNumbers(), contact2
.getFaxNumbers());
189 mergeList(this.getPhoneNumbers(), contact2
.getPhoneNumbers());
190 mergeList(this.getUrls(), contact2
.getUrls());
191 for (Address address
: contact2
.getAddresses()){
193 if (this.addresses
== null){
194 this.addresses
= new HashSet
<>();
196 this.addresses
.add(address
.clone());
197 } catch (CloneNotSupportedException e
) {
198 throw new MergeException("Address must implement Cloneable");
204 private void mergeList(List list1
, List list2
){
205 for (Object obj2
: list2
){
206 if (! list1
.contains(obj2
)){
213 * True, if no contact data exists in any of the lists (email, phone, ...).
216 public boolean isEmpty(){
217 if (isEmpty(emailAddresses
) && isEmpty(faxNumbers
) && isEmpty(phoneNumbers
)
218 && isEmpty(urls
) && isEmpty(addresses
)){
225 private boolean isEmpty(Collection
<?
extends Object
> collection
) {
226 return collection
== null || collection
.isEmpty();
230 * Returns the set of postal {@link Address addresses} belonging to <i>this</i> contact.
231 * A {@link Person person} or an {@link Institution institution} cannot have more than one contact,
232 * but a contact may include several postal addresses.
234 * @return the set of postal addresses
237 public Set
<Address
> getAddresses(){
238 return this.addresses
;
242 * Adds a new postal {@link Address address} to the set of postal addresses of <i>this</i> contact.
244 * @param address the address to be added
245 * @see #getAddresses()
248 public void addAddress(Address address
){
249 if (address
!= null){
250 getAddresses().add(address
);
254 public Address
addAddress(String street
, String postcode
, String locality
,
255 Country country
, String pobox
, String region
, Point location
){
256 Address newAddress
= Address
.NewInstance(country
, locality
, pobox
, postcode
, region
, street
, location
);
257 getAddresses().add(newAddress
);
262 * Removes one element from the set of postal addresses of <i>this</i> contact.
264 * @param address the postal address of <i>this</i> contact which should be deleted
265 * @see #getAddresses()
267 public void removeAddress(Address address
){
268 getAddresses().remove(address
);
273 * Returns the List of strings representing the electronic mail addresses
274 * included in <i>this</i> contact.
276 public List
<String
> getEmailAddresses(){
277 if(this.emailAddresses
== null) {
278 this.emailAddresses
= new ArrayList
<>();
280 return this.emailAddresses
;
284 * @see #getEmailAddress()
286 public void addEmailAddress(String emailAddress
){
287 getEmailAddresses().add(emailAddress
);
291 * Removes one element from the list of email addresses of <i>this</i> contact.
293 * @param emailAddress the email address of <i>this</i> contact which should be deleted
294 * @see #getEmailAddresses()
296 public void removeEmailAddress(String emailAddress
){
297 getEmailAddresses().remove(emailAddress
);
301 // * Returns the list of {@link URI URIs} representing this contact
302 // * included in <i>this</i> contact.
304 // @Transient //TODO preliminary workaround as we get LazyInit Exception in JSON #4444
305 // public List<URI> getUrls(){
306 // List<URI> result = new ArrayList<URI>();
307 // if(this.urls != null) {
308 // for (String uri : this.urls){
309 // result.add(URI.create(uri));
316 * Returns the list of {@link URI URIs} representing this contact
317 * included in <i>this</i> contact.
319 public List
<String
> getUrls(){
326 public void addUrl(URI url
){
327 this.urls
.add(url
.toString());
331 * Removes one element from the list of urls of <i>this</i> contact.
333 * @param url the url of <i>this</i> contact which should be deleted
336 public void removeUrl(URI url
){
337 this.urls
.remove(url
.toString());
342 * Returns the list of strings representing the phone numbers
343 * included in <i>this</i> contact.
345 public List
<String
> getPhoneNumbers(){
346 if(this.phoneNumbers
== null) {
347 this.phoneNumbers
= new ArrayList
<>();
349 return this.phoneNumbers
;
355 public void addPhoneNumber(String phoneNumber
){
356 getPhoneNumbers().add(phoneNumber
);
360 * Removes one element from the list of phone numbers of <i>this</i> contact.
362 * @param phoneNumber the phone number of <i>this</i> contact which should be deleted
363 * @see #getPhoneNumber()
365 public void removePhoneNumber(String phoneNumber
){
366 getPhoneNumbers().remove(phoneNumber
);
370 * Returns the list of strings representing the telefax numbers
371 * included in <i>this</i> contact.
373 public List
<String
> getFaxNumbers(){
374 if(this.faxNumbers
== null) {
375 this.faxNumbers
= new ArrayList
<>();
377 return this.faxNumbers
;
381 * @see #getFaxNumbers()
383 public void addFaxNumber(String faxNumber
){
384 getFaxNumbers().add(faxNumber
);
388 * Removes one element from the list of telefax numbers of <i>this</i> contact.
390 * @param faxNumber the telefax number of <i>this</i> contact which should be deleted
391 * @see #getFaxNumber()
393 public void removeFaxNumber(String faxNumber
){
394 getFaxNumbers().remove(faxNumber
);
397 //*********************** CLONE ********************************************************/
400 * Clones <i>this</i> Contact. This is a shortcut that enables to create
401 * a new instance that differs only slightly from <i>this</i> Contact.
404 * @see java.lang.Object#clone()
407 public Contact
clone() {
409 Contact result
= (Contact
) super.clone();
410 result
.addresses
= new HashSet
<>();
411 for (Address adr
: this.addresses
){
412 result
.addAddress(adr
.clone());
414 //no changes to emailAdresses, faxnumbers, phonenumbers, urls
416 }catch (CloneNotSupportedException e
){
417 logger
.warn("Object does not implement cloneable");