merge cdmlib-3.4 branch into trunk
[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.HashSet;
16 import java.util.List;
17 import java.util.Set;
18
19 import javax.persistence.Column;
20 import javax.persistence.ElementCollection;
21 import javax.persistence.Embeddable;
22 import javax.persistence.FetchType;
23 import javax.persistence.OneToMany;
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;
31
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.log4j.Logger;
34 import org.hibernate.annotations.Cascade;
35 import org.hibernate.annotations.CascadeType;
36 import org.hibernate.envers.Audited;
37
38 import eu.etaxonomy.cdm.model.location.Country;
39 import eu.etaxonomy.cdm.model.location.Point;
40 import eu.etaxonomy.cdm.strategy.merge.MergeException;
41
42 /**
43 * The class for information on how to approach a {@link Person person} or an {@link Institution institution}.
44 * It includes telecommunication data and an electronic as well as
45 * multiple postal addresses.
46 * <P>
47 * This class corresponds to: <ul>
48 * <li> ContactDetails according to the TDWG ontology
49 * <li> Contact (partially) according to the ABCD schema
50 * </ul>
51 *
52 * @author m.doering
53 * @version 1.0
54 * @created 08-Nov-2007 13:06:18
55 */
56 @XmlAccessorType(XmlAccessType.FIELD)
57 @XmlType(name = "Contact", propOrder = {
58 "emailAddresses",
59 "urls",
60 "phoneNumbers",
61 "faxNumbers",
62 "addresses"
63 })
64 @XmlRootElement(name = "Contact")
65 @Embeddable
66 @Audited
67 public class Contact implements Serializable, Cloneable {
68 private static final long serialVersionUID = -1851305307069277625L;
69 private static final Logger logger = Logger.getLogger(Contact.class);
70
71
72 @XmlElementWrapper(name = "EmailAddresses", nillable = true)
73 @XmlElement(name = "EmailAddress")
74 @ElementCollection(fetch = FetchType.LAZY)
75 @Column(name = "contact_emailaddresses_element")
76 private List<String> emailAddresses;
77
78 @XmlElementWrapper(name = "URLs", nillable = true)
79 @XmlElement(name = "URL")
80 @XmlSchemaType(name = "anyURI")
81 @ElementCollection(fetch = FetchType.LAZY)
82 @Column(name = "contact_urls_element", length=330)
83 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
84 private List<String> urls = new ArrayList<String>();
85
86 @XmlElementWrapper(name = "PhoneNumbers", nillable = true)
87 @XmlElement(name = "PhoneNumber")
88 @ElementCollection(fetch = FetchType.LAZY)
89 @Column(name = "contact_phonenumbers_element")
90 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE})
91 private List<String> phoneNumbers;
92
93 @XmlElementWrapper(name = "FaxNumbers", nillable = true)
94 @XmlElement(name = "FaxNumber")
95 @ElementCollection(fetch = FetchType.LAZY)
96 @Column(name = "contact_faxnumbers_element")
97 private List<String> faxNumbers;
98
99 @XmlElementWrapper(name = "Addresses", nillable = true)
100 @XmlElement(name = "Address")
101 @OneToMany(fetch = FetchType.LAZY, orphanRemoval=true)
102 @Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
103 protected Set<Address> addresses;
104
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> emailAdresses,
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 (emailAdresses != null){
157 result.emailAddresses = emailAdresses;
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
174 /**
175 * Class constructor.
176 */
177 public Contact() {
178 }
179
180
181 public void merge(Contact contact2) throws MergeException{
182 if (contact2 != null){
183 mergeList(this.getEmailAddresses(), contact2.getEmailAddresses());
184 mergeList(this.getFaxNumbers(), contact2.getFaxNumbers());
185 mergeList(this.getPhoneNumbers(), contact2.getPhoneNumbers());
186 mergeList(this.getUrls(), contact2.getUrls());
187 for (Address address : contact2.getAddresses()){
188 try {
189 this.addresses.add((Address)address.clone());
190 } catch (CloneNotSupportedException e) {
191 throw new MergeException("Address must implement Cloneable");
192 }
193 }
194 }
195 }
196
197 private void mergeList(List list1, List list2){
198 for (Object obj2 : list2){
199 if (! list1.contains(obj2)){
200 list1.add(obj2);
201 }
202 }
203 }
204
205
206 /**
207 * Returns the set of postal {@link Address addresses} belonging to <i>this</i> contact.
208 * A {@link Person person} or an {@link Institution institution} cannot have more than one contact,
209 * but a contact may include several postal addresses.
210 *
211 * @return the set of postal addresses
212 * @see Address
213 */
214 public Set<Address> getAddresses(){
215 if(this.addresses == null) {
216 this.addresses = new HashSet<Address>();
217 }
218 return this.addresses;
219 }
220
221 /**
222 * Adds a new postal {@link Address address} to the set of postal addresses of <i>this</i> contact.
223 *
224 * @param address the address to be added
225 * @see #getAddresses()
226 * @see Address
227 */
228 public void addAddress(Address address){
229 if (address != null){
230 getAddresses().add(address);
231 }
232 }
233
234 public Address addAddress(String street, String postcode, String locality,
235 Country country, String pobox, String region, Point location){
236 Address newAddress = Address.NewInstance(country, locality, pobox, postcode, region, street, location);
237 getAddresses().add(newAddress);
238 return newAddress;
239 }
240
241 /**
242 * Removes one element from the set of postal addresses of <i>this</i> contact.
243 *
244 * @param address the postal address of <i>this</i> contact which should be deleted
245 * @see #getAddresses()
246 */
247 public void removeAddress(Address address){
248 getAddresses().remove(address);
249 }
250
251
252 /**
253 * Returns the List of strings representing the electronic mail addresses
254 * included in <i>this</i> contact.
255 */
256 public List<String> getEmailAddresses(){
257 if(this.emailAddresses == null) {
258 this.emailAddresses = new ArrayList<String>();
259 }
260 return this.emailAddresses;
261 }
262
263 /**
264 * @see #getEmailAddress()
265 */
266 public void addEmailAddress(String emailAddress){
267 getEmailAddresses().add(emailAddress);
268 }
269
270 /**
271 * Removes one element from the list of email addresses of <i>this</i> contact.
272 *
273 * @param emailAddress the email address of <i>this</i> contact which should be deleted
274 * @see #getEmailAddresses()
275 */
276 public void removeEmailAddress(String emailAddress){
277 getEmailAddresses().remove(emailAddress);
278 }
279
280 /**
281 * Returns the list of strings representing the "Uniform Resource Locators" (urls)
282 * included in <i>this</i> contact.
283 */
284 public List<URI> getUrls(){
285 List<URI> result = new ArrayList<URI>();
286 if(this.urls != null) {
287 for (String uri : this.urls){
288 result.add(URI.create(uri));
289 }
290 }
291 return result;
292 }
293
294 /**
295 * @see #getUrls()
296 */
297 public void addUrl(URI url){
298 this.urls.add(url.toString());
299 }
300
301 /**
302 * Removes one element from the list of urls of <i>this</i> contact.
303 *
304 * @param url the url of <i>this</i> contact which should be deleted
305 * @see #getUrls()
306 */
307 public void removeUrl(URI url){
308 this.urls.remove(url.toString());
309 }
310
311 /**
312 * Returns the list of strings representing the phone numbers
313 * included in <i>this</i> contact.
314 */
315 public List<String> getPhoneNumbers(){
316 if(this.phoneNumbers == null) {
317 this.phoneNumbers = new ArrayList<String>();
318 }
319 return this.phoneNumbers;
320 }
321
322 /**
323 * @see #getPhone()
324 */
325 public void addPhoneNumber(String phoneNumber){
326 getPhoneNumbers().add(phoneNumber);
327 }
328
329 /**
330 * Removes one element from the list of phone numbers of <i>this</i> contact.
331 *
332 * @param phoneNumber the phone number of <i>this</i> contact which should be deleted
333 * @see #getPhoneNumber()
334 */
335 public void removePhoneNumber(String phoneNumber){
336 getPhoneNumbers().remove(phoneNumber);
337 }
338
339 /**
340 * Returns the list of strings representing the telefax numbers
341 * included in <i>this</i> contact.
342 */
343 public List<String> getFaxNumbers(){
344 if(this.faxNumbers == null) {
345 this.faxNumbers = new ArrayList<String>();
346 }
347 return this.faxNumbers;
348 }
349
350 /**
351 * @see #getFaxNumbers()
352 */
353 public void addFaxNumber(String faxNumber){
354 getFaxNumbers().add(faxNumber);
355 }
356
357 /**
358 * Removes one element from the list of telefax numbers of <i>this</i> contact.
359 *
360 * @param faxNumber the telefax number of <i>this</i> contact which should be deleted
361 * @see #getFaxNumber()
362 */
363 public void removeFaxNumber(String faxNumber){
364 getFaxNumbers().remove(faxNumber);
365 }
366
367 //*********************** CLONE ********************************************************/
368
369 /**
370 * Clones <i>this</i> Contact. This is a shortcut that enables to create
371 * a new instance that differs only slightly from <i>this</i> Contact.
372 *
373 *
374 * @see java.lang.Object#clone()
375 */
376 @Override
377 public Object clone() {
378 try{
379 Contact result = (Contact) super.clone();
380 result.addresses = new HashSet<Address>();
381 for (Address adr : this.addresses){
382 result.addAddress((Address)adr.clone());
383 }
384 //no changes to emailAdresses, faxNumbers, phoneNumbers, urls
385 return result;
386 }catch (CloneNotSupportedException e){
387 logger.warn("Object does not implement cloneable");
388 e.printStackTrace();
389 return null;
390 }
391 }
392 }