revert contact URLs #3920, #4444
[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.persistence.Transient;
25 import javax.xml.bind.annotation.XmlAccessType;
26 import javax.xml.bind.annotation.XmlAccessorType;
27 import javax.xml.bind.annotation.XmlElement;
28 import javax.xml.bind.annotation.XmlElementWrapper;
29 import javax.xml.bind.annotation.XmlRootElement;
30 import javax.xml.bind.annotation.XmlSchemaType;
31 import javax.xml.bind.annotation.XmlType;
32
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.log4j.Logger;
35 import org.hibernate.annotations.Cascade;
36 import org.hibernate.annotations.CascadeType;
37 import org.hibernate.envers.Audited;
38
39 import eu.etaxonomy.cdm.model.location.Country;
40 import eu.etaxonomy.cdm.model.location.Point;
41 import eu.etaxonomy.cdm.strategy.merge.MergeException;
42
43 /**
44 * The class for information on how to approach a {@link Person person} or an {@link Institution institution}.
45 * It includes telecommunication data and an electronic as well as
46 * multiple postal addresses.
47 * <P>
48 * This class corresponds to: <ul>
49 * <li> ContactDetails according to the TDWG ontology
50 * <li> Contact (partially) according to the ABCD schema
51 * </ul>
52 *
53 * @author m.doering
54 * @version 1.0
55 * @created 08-Nov-2007 13:06:18
56 */
57 @XmlAccessorType(XmlAccessType.FIELD)
58 @XmlType(name = "Contact", propOrder = {
59 "emailAddresses",
60 "urls",
61 "phoneNumbers",
62 "faxNumbers",
63 "addresses"
64 })
65 @XmlRootElement(name = "Contact")
66 @Embeddable
67 @Audited
68 public class Contact implements Serializable, Cloneable {
69 private static final long serialVersionUID = -1851305307069277625L;
70 private static final Logger logger = Logger.getLogger(Contact.class);
71
72
73 @XmlElementWrapper(name = "EmailAddresses", nillable = true)
74 @XmlElement(name = "EmailAddress")
75 @ElementCollection(fetch = FetchType.LAZY)
76 @Column(name = "contact_emailaddresses_element")
77 private List<String> emailAddresses;
78
79 @XmlElementWrapper(name = "URLs", nillable = true)
80 @XmlElement(name = "URL")
81 @XmlSchemaType(name = "anyURI")
82 @ElementCollection(fetch = FetchType.LAZY)
83 @Column(name = "contact_urls_element" /*, length=330 */) //length >255 does not work in InnoDB AUD tables for Key length of (REV, id, url) key
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 {@link URI URIs} representing this contact
282 // * included in <i>this</i> contact.
283 // */
284 // @Transient //TODO preliminary workaround as we get LazyInit Exception in JSON #4444
285 // public List<URI> getUrls(){
286 // List<URI> result = new ArrayList<URI>();
287 // if(this.urls != null) {
288 // for (String uri : this.urls){
289 // result.add(URI.create(uri));
290 // }
291 // }
292 // return result;
293 // }
294
295 /**
296 * Returns the list of {@link URI URIs} representing this contact
297 * included in <i>this</i> contact.
298 */
299 public List<String> getUrls(){
300 return this.urls;
301 }
302
303 /**
304 * @see #getUrls()
305 */
306 public void addUrl(URI url){
307 this.urls.add(url.toString());
308 }
309
310 /**
311 * Removes one element from the list of urls of <i>this</i> contact.
312 *
313 * @param url the url of <i>this</i> contact which should be deleted
314 * @see #getUrls()
315 */
316 public void removeUrl(URI url){
317 this.urls.remove(url.toString());
318 }
319
320
321 /**
322 * Returns the list of strings representing the phone numbers
323 * included in <i>this</i> contact.
324 */
325 public List<String> getPhoneNumbers(){
326 if(this.phoneNumbers == null) {
327 this.phoneNumbers = new ArrayList<String>();
328 }
329 return this.phoneNumbers;
330 }
331
332 /**
333 * @see #getPhone()
334 */
335 public void addPhoneNumber(String phoneNumber){
336 getPhoneNumbers().add(phoneNumber);
337 }
338
339 /**
340 * Removes one element from the list of phone numbers of <i>this</i> contact.
341 *
342 * @param phoneNumber the phone number of <i>this</i> contact which should be deleted
343 * @see #getPhoneNumber()
344 */
345 public void removePhoneNumber(String phoneNumber){
346 getPhoneNumbers().remove(phoneNumber);
347 }
348
349 /**
350 * Returns the list of strings representing the telefax numbers
351 * included in <i>this</i> contact.
352 */
353 public List<String> getFaxNumbers(){
354 if(this.faxNumbers == null) {
355 this.faxNumbers = new ArrayList<String>();
356 }
357 return this.faxNumbers;
358 }
359
360 /**
361 * @see #getFaxNumbers()
362 */
363 public void addFaxNumber(String faxNumber){
364 getFaxNumbers().add(faxNumber);
365 }
366
367 /**
368 * Removes one element from the list of telefax numbers of <i>this</i> contact.
369 *
370 * @param faxNumber the telefax number of <i>this</i> contact which should be deleted
371 * @see #getFaxNumber()
372 */
373 public void removeFaxNumber(String faxNumber){
374 getFaxNumbers().remove(faxNumber);
375 }
376
377 //*********************** CLONE ********************************************************/
378
379 /**
380 * Clones <i>this</i> Contact. This is a shortcut that enables to create
381 * a new instance that differs only slightly from <i>this</i> Contact.
382 *
383 *
384 * @see java.lang.Object#clone()
385 */
386 @Override
387 public Object clone() {
388 try{
389 Contact result = (Contact) super.clone();
390 result.addresses = new HashSet<Address>();
391 for (Address adr : this.addresses){
392 result.addAddress((Address)adr.clone());
393 }
394 //no changes to emailAdresses, faxNumbers, phoneNumbers, urls
395 return result;
396 }catch (CloneNotSupportedException e){
397 logger.warn("Object does not implement cloneable");
398 e.printStackTrace();
399 return null;
400 }
401 }
402 }