001/*
002 * Copyright 2014 Global Biodiversity Information Facility (GBIF)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.gbif.api.model.checklistbank;
017
018import org.gbif.api.jackson.ExtensionKeyDeserializer;
019import org.gbif.api.jackson.ExtensionSerializer;
020import org.gbif.api.jackson.TermMapListDeserializer;
021import org.gbif.api.jackson.TermMapListSerializer;
022import org.gbif.api.vocabulary.Extension;
023import org.gbif.dwc.terms.Term;
024import org.gbif.dwc.terms.TermFactory;
025
026import java.util.Date;
027import java.util.List;
028import java.util.Map;
029
030import javax.annotation.Nullable;
031import javax.validation.constraints.NotNull;
032
033import com.google.common.base.Objects;
034import com.google.common.base.Strings;
035import com.google.common.collect.Maps;
036import org.codehaus.jackson.annotate.JsonAnyGetter;
037import org.codehaus.jackson.annotate.JsonAnySetter;
038import org.codehaus.jackson.annotate.JsonIgnore;
039import org.codehaus.jackson.map.annotate.JsonDeserialize;
040import org.codehaus.jackson.map.annotate.JsonSerialize;
041
042import static com.google.common.base.Preconditions.checkNotNull;
043
044public class VerbatimNameUsage {
045  private Integer key;
046  // the verbatim taxon fields for the usage
047  private Map<Term, String> fields = Maps.newHashMap();
048  // the verbatim extension records as read by a dwc star record, keyed on the extension
049  private Map<Extension, List<Map<Term, String>>> extensions = Maps.newHashMap();
050
051  private Date lastCrawled;
052
053  /**
054   * @return The name usage key
055   */
056  @NotNull
057  public Integer getKey() {
058    return key;
059  }
060
061  public void setKey(Integer key) {
062    this.key = key;
063  }
064
065  /**
066   * A map of extension records, holding all verbatim extension terms.
067   */
068  @NotNull
069  @JsonSerialize(keyUsing = ExtensionSerializer.class, contentUsing = TermMapListSerializer.class)
070  @JsonDeserialize(keyUsing = ExtensionKeyDeserializer.class, contentUsing = TermMapListDeserializer.class)
071  public Map<Extension, List<Map<Term, String>>> getExtensions() {
072    return extensions;
073  }
074
075  public void setExtensions(Map<Extension, List<Map<Term, String>>> extensions) {
076    this.extensions = extensions;
077  }
078
079  /**
080   * A map holding all verbatim core terms.
081   */
082  @NotNull
083  @JsonIgnore
084  public Map<Term, String> getFields() {
085    return fields;
086  }
087
088  public void setFields(Map<Term, String> fields) {
089    this.fields = fields;
090  }
091
092  @Nullable
093  /**
094   * The date this record was last crawled during clb indexing.
095   */
096  public Date getLastCrawled() {
097    return lastCrawled == null ? null : new Date(lastCrawled.getTime());
098  }
099
100  public void setLastCrawled(@Nullable Date lastCrawled) {
101    this.lastCrawled = lastCrawled == null ? null : new Date(lastCrawled.getTime());
102  }
103
104  /**
105   * Get the value of a specific field (Term).
106   */
107  @Nullable
108  public String getCoreField(Term term) {
109    checkNotNull(term, "term can't be null");
110    return fields.get(term);
111  }
112
113  /**
114   * @return true if a verbatim field exists and is not null or an empty string
115   */
116  public boolean hasCoreField(Term term) {
117    checkNotNull(term, "term can't be null");
118    return !Strings.isNullOrEmpty(fields.get(term));
119  }
120
121  /**
122   * @return true if at least one extension record exists
123   */
124  public boolean hasExtension(Extension extension) {
125    return extensions.containsKey(extension) && !extensions.get(extension).isEmpty();
126  }
127
128  public boolean hasExtension(Term term) {
129    checkNotNull(term, "term can't be null");
130    Extension ext = Extension.fromRowType(term.qualifiedName());
131    return ext == null ? false : hasExtension(ext);
132  }
133
134  /**
135   * For setting a specific field without having to replace the entire fields Map.
136   *
137   * @param term the field to set
138   * @param fieldValue the field's value
139   */
140  public void setCoreField(Term term, @Nullable String fieldValue) {
141    checkNotNull(term, "term can't be null");
142    fields.put(term, fieldValue);
143  }
144
145  /**
146   * This private method is only for deserialization via jackson and not exposed anywhere else!
147   */
148  @JsonAnySetter
149  private void addJsonVerbatimField(String key, String value) {
150    Term t = TermFactory.instance().findTerm(key);
151    fields.put(t, value);
152  }
153
154  /**
155   * This private method is only for serialization via jackson and not exposed anywhere else!
156   * It maps the verbatimField terms into properties with their full qualified name.
157   */
158  @JsonAnyGetter
159  private Map<String, String> jsonVerbatimFields() {
160    Map<String, String> extendedProps = Maps.newHashMap();
161    for (Map.Entry<Term, String> prop : fields.entrySet()) {
162      extendedProps.put(prop.getKey().qualifiedName(), prop.getValue());
163    }
164    return extendedProps;
165  }
166
167
168
169
170  @Override
171  public boolean equals(Object object) {
172    if (this == object) {
173      return true;
174    }
175    if (!(object instanceof VerbatimNameUsage)) {
176      return false;
177    }
178
179    VerbatimNameUsage that = (VerbatimNameUsage) object;
180    return Objects.equal(this.key, that.key)
181           && Objects.equal(this.fields, that.fields)
182           && Objects.equal(this.extensions, that.extensions)
183           && Objects.equal(this.lastCrawled, that.lastCrawled);
184  }
185
186  @Override
187  public int hashCode() {
188    return Objects.hashCode(key,
189                            fields,
190                            extensions,
191                            lastCrawled);
192  }
193
194  @Override
195  public String toString() {
196    return Objects.toStringHelper(this)
197      .add("key", key)
198      .add("fields", fields)
199      .add("extensions", extensions)
200      .add("lastCrawled", lastCrawled)
201      .toString();
202  }
203
204}