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