001/*
002 * Copyright 2013 Global Biodiversity Information Facility (GBIF)
003 * Licensed under the Apache License, Version 2.0 (the "License");
004 * you may not use this file except in compliance with the License.
005 * You may obtain a copy of the License at
006 * http://www.apache.org/licenses/LICENSE-2.0
007 * Unless required by applicable law or agreed to in writing, software
008 * distributed under the License is distributed on an "AS IS" BASIS,
009 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010 * See the License for the specific language governing permissions and
011 * limitations under the License.
012 */
013package org.gbif.api.model.registry;
014
015import org.gbif.api.vocabulary.ContactType;
016import org.gbif.api.vocabulary.Country;
017
018import java.net.URI;
019import java.util.Date;
020import java.util.List;
021import javax.annotation.Nullable;
022import javax.validation.constraints.NotNull;
023import javax.validation.constraints.Null;
024import javax.validation.constraints.Size;
025
026import com.google.common.base.Objects;
027import com.google.common.base.Strings;
028import com.google.common.collect.Lists;
029import org.apache.commons.lang3.StringUtils;
030
031// TODO: Should have a cross-field validation for key & created
032public class Contact implements Address, LenientEquals<Contact> {
033
034  private Integer key;
035  private ContactType type;
036  private boolean primary;
037  private List<String> userId = Lists.newArrayList();
038  private String firstName;
039  private String lastName;
040  private List<String> position = Lists.newArrayList();
041  private String description;
042  private List<String> email = Lists.newArrayList();
043  private List<String> phone = Lists.newArrayList();
044  private List<URI> homepage = Lists.newArrayList();
045  private String organization;
046  private List<String> address = Lists.newArrayList();
047  private String city;
048  private String province;
049  private Country country;
050  private String postalCode;
051  private String createdBy;
052  private String modifiedBy;
053  private Date created;
054  private Date modified;
055
056  @Null(groups = {PrePersist.class})
057  @NotNull(groups = {PostPersist.class})
058  public Integer getKey() {
059    return key;
060  }
061
062  public void setKey(Integer key) {
063    this.key = key;
064  }
065
066  @Nullable
067  public ContactType getType() {
068    return type;
069  }
070
071  public void setType(ContactType type) {
072    this.type = type;
073  }
074
075  public boolean isPrimary() {
076    return primary;
077  }
078
079  public void setPrimary(boolean primary) {
080    this.primary = primary;
081  }
082
083  @Nullable
084  public List<String> getUserId() {
085    return userId;
086  }
087
088  public void setUserId(List<String> userId) {
089    this.userId = userId;
090  }
091
092  public void addUserId(String userId) {
093    this.userId.add(userId);
094  }
095
096  /**
097   * Adds a new user id that is assembled from a directory name and a local id within it.
098   * Format used by EML.
099   * The directory should be a valid URI, if it's not, it will be ignored by this method.
100   *
101   * @param directory identifier for the directory, preferably a URL domain like http://orcid.org
102   * @param id the identifier in that directory
103   */
104  public void addUserId(String directory, String id) {
105    if (!Strings.isNullOrEmpty(id)) {
106      if (Strings.isNullOrEmpty(directory)) {
107        userId.add(id);
108      } else {
109        try {
110          URI dir = URI.create(directory);
111          if (dir.isAbsolute()) {
112            String dir2 = dir.toString();
113            if (!dir2.endsWith("/") && !dir2.endsWith("=")) {
114              dir2 = dir2 + "/";
115            }
116            userId.add(dir2 + id);
117          } else {
118            userId.add(dir + ":" + id);
119          }
120        }
121        catch (IllegalArgumentException iaEx) {
122          //in case the directory is not a valid url keep only the user id
123          userId.add(id);
124        }
125      }
126    }
127  }
128
129  @Nullable
130  @Size(min = 1)
131  public String getFirstName() {
132    return firstName;
133  }
134
135  public void setFirstName(String firstName) {
136    this.firstName = firstName;
137  }
138
139  @Nullable
140  @Size(min = 1)
141  public String getLastName() {
142    return lastName;
143  }
144
145  public void setLastName(String lastName) {
146    this.lastName = lastName;
147  }
148
149  /**
150   * Compute and returns the complete name in the form: FirstName LastName.
151   * Since all parts are optional, this method can return an empty string (but never null)
152   *
153   * @return the non-empty parts of FirstName LastName or empty string if none
154   */
155  public String computeCompleteName() {
156    return org.gbif.utils.text.StringUtils.thenJoin(StringUtils::trimToNull, firstName, lastName);
157  }
158
159  public List<String> getPosition() {
160    return position;
161  }
162
163  public void setPosition(List<String> position) {
164    this.position = position;
165  }
166
167  public void addPosition(String position) {
168    this.position.add(position);
169  }
170
171  @Nullable
172  public String getDescription() {
173    return description;
174  }
175
176  public void setDescription(String description) {
177    this.description = description;
178  }
179
180  @Override
181  @Nullable
182  public List<String> getEmail() {
183    return email;
184  }
185
186  @Override
187  public void setEmail(List<String> email) {
188    this.email = email;
189  }
190
191  public void addEmail(String email) {
192    this.email.add(email);
193  }
194
195  @Override
196  @Nullable
197  public List<String> getPhone() {
198    return phone;
199  }
200
201  @Override
202  public void setPhone(List<String> phone) {
203    this.phone = phone;
204  }
205
206  public void addPhone(String phone) {
207    this.phone.add(phone);
208  }
209
210  @Override
211  public List<String> getAddress() {
212    return address;
213  }
214
215  @Override
216  public void setAddress(List<String> address) {
217    this.address = address;
218  }
219
220  public void addAddress(String address) {
221    this.address.add(address);
222  }
223
224  @Override
225  public String getCity() {
226    return city;
227  }
228
229  @Override
230  public void setCity(String city) {
231    this.city = city;
232  }
233
234  @Override
235  public String getProvince() {
236    return province;
237  }
238
239  @Override
240  public void setProvince(String province) {
241    this.province = province;
242  }
243
244  @Override
245  public Country getCountry() {
246    return country;
247  }
248
249  @Override
250  public void setCountry(Country country) {
251    this.country = country;
252  }
253
254  @Override
255  public String getPostalCode() {
256    return postalCode;
257  }
258
259  @Override
260  public void setPostalCode(String postalCode) {
261    this.postalCode = postalCode;
262  }
263
264  @Override
265  @Nullable
266  @Size(min = 2)
267  public String getOrganization() {
268    return organization;
269  }
270
271  @Override
272  public void setOrganization(String organization) {
273    this.organization = organization;
274  }
275
276  @Override
277  public List<URI> getHomepage() {
278    return homepage;
279  }
280
281  @Override
282  public void setHomepage(List<URI> homepage) {
283    this.homepage = homepage;
284  }
285
286  public void addHomepage(URI homepage) {
287    this.homepage.add(homepage);
288  }
289
290  @Size(min = 3)
291  public String getCreatedBy() {
292    return createdBy;
293  }
294
295  public void setCreatedBy(String createdBy) {
296    this.createdBy = createdBy;
297  }
298
299  @Size(min = 3)
300  public String getModifiedBy() {
301    return modifiedBy;
302  }
303
304  public void setModifiedBy(String modifiedBy) {
305    this.modifiedBy = modifiedBy;
306  }
307
308  @Null(groups = {PrePersist.class})
309  @NotNull(groups = {PostPersist.class})
310  public Date getCreated() {
311    return created;
312  }
313
314  public void setCreated(Date created) {
315    this.created = created;
316  }
317
318  @Null(groups = {PrePersist.class})
319  @NotNull(groups = {PostPersist.class})
320  public Date getModified() {
321    return modified;
322  }
323
324  public void setModified(Date modified) {
325    this.modified = modified;
326  }
327
328  @Override
329  public int hashCode() {
330    return Objects
331      .hashCode(key, type, primary, userId, firstName, lastName, position, description, email, phone, homepage,
332                organization, address, city, province, country, postalCode, createdBy, modifiedBy, created, modified);
333  }
334
335  @Override
336  public boolean equals(Object object) {
337    if (this == object) {
338      return true;
339    }
340
341    if (object instanceof Contact) {
342      Contact that = (Contact) object;
343      return lenientEquals(that)
344        && Objects.equal(this.key, that.key)
345        && Objects.equal(this.primary, that.primary)
346        && Objects.equal(this.createdBy, that.createdBy)
347        && Objects.equal(this.modifiedBy, that.modifiedBy)
348        && Objects.equal(this.created, that.created)
349        && Objects.equal(this.modified, that.modified);
350    }
351    return false;
352  }
353
354  @Override
355  public String toString() {
356    return Objects.toStringHelper(this).add("key", key).add("type", type)
357      .add("primary", primary)
358      .add("userId", userId)
359      .add("firstName", firstName).add("lastName", lastName).add("position", position)
360      .add("description", description).add("email", email).add("phone", phone)
361      .add("homepage", homepage)
362      .add("organization", organization)
363      .add("address", address).add("city", city).add("province", province).add("country", country)
364      .add("postalCode", postalCode)
365      .add("createdBy", createdBy).add("modifiedBy", modifiedBy).add("created", created)
366      .add("modified", modified).toString();
367  }
368
369  /**
370   * This implementation of the {@link #equals(Object)} method does only check <em>business equality</em> and disregards
371   * automatically set and maintained fields like {@code createdBy, key} and others.
372   */
373  @Override
374  public boolean lenientEquals(Contact contact) {
375    if (this == contact) {
376      return true;
377    }
378
379    return Objects.equal(type, contact.type)
380      && Objects.equal(primary, contact.primary)
381      && Objects.equal(userId, contact.userId)
382      && Objects.equal(firstName, contact.firstName)
383      && Objects.equal(lastName, contact.lastName)
384      && Objects.equal(position, contact.position)
385      && Objects.equal(description, contact.description)
386      && Objects.equal(email, contact.email)
387      && Objects.equal(phone, contact.phone)
388      && Objects.equal(homepage, contact.homepage)
389      && Objects.equal(organization, contact.organization)
390      && Objects.equal(address, contact.address)
391      && Objects.equal(city, contact.city)
392      && Objects.equal(province, contact.province)
393      && Objects.equal(country, contact.country)
394      && Objects.equal(postalCode, contact.postalCode);
395  }
396
397}