/* * This is eMonocot, a global online biodiversity information resource. * * Copyright © 2011–2015 The Board of Trustees of the Royal Botanic Gardens, Kew and The University of Oxford * * eMonocot is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * eMonocot is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * The complete text of the GNU Affero General Public License is in the source repository as the file * ‘COPYING’. It is also available from <http://www.gnu.org/licenses/>. */ package org.emonocot.model; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.Lob; import javax.persistence.ManyToMany; import javax.persistence.OneToMany; import javax.persistence.Transient; import javax.validation.constraints.Size; import org.apache.solr.common.SolrInputDocument; import org.emonocot.model.constants.TypeDesignationType; import org.emonocot.model.marshall.json.TaxonDeserializer; import org.emonocot.model.marshall.json.TaxonSerializer; import org.gbif.ecat.voc.Rank; import org.gbif.ecat.voc.Sex; import org.gbif.ecat.voc.TypeStatus; import org.geotools.geometry.jts.JTSFactoryFinder; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.Type; import org.hibernate.annotations.Where; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.io.WKTWriter; /** * * @author ben * */ @Entity public class TypeAndSpecimen extends BaseData implements NonOwned, Searchable { private static final long serialVersionUID = -843014945343629009L; private static final Logger logger = LoggerFactory.getLogger(TypeAndSpecimen.class); private Long id; private TypeStatus typeStatus; private TypeDesignationType typeDesignationType; private String typeDesignatedBy; private String scientificName; private Rank taxonRank; private String bibliographicCitation; private String institutionCode; private String collectionCode; private String catalogNumber; private String locality; private Sex sex; private String recordedBy; private String source; private String verbatimEventDate; private String verbatimLabel; private String verbatimLongitude; private String verbatimLatitude; private Double decimalLatitude; private Double decimalLongitude; private Point location; /** * @return */ private Set<Taxon> taxa = new HashSet<Taxon>(); private Set<Annotation> annotations = new HashSet<Annotation>(); @Override @Id @GeneratedValue(generator = "table-hilo", strategy = GenerationType.TABLE) public Long getId() { return id; } /** * @return the decimalLatitude */ public Double getDecimalLatitude() { return decimalLatitude; } /** * @param decimalLatitude the decimalLatitude to set */ public void setDecimalLatitude(Double decimalLatitude) { this.decimalLatitude = decimalLatitude; updateLocation(); } /** * @return the location */ @Type(type = "spatialType") public Point getLocation() { return location; } /** * @param location the location to set */ public void setLocation(Point location) { this.location = location; } /** * @return the decimalLongitude */ public Double getDecimalLongitude() { return decimalLongitude; } /** * @param decimalLongitude the decimalLongitude to set */ public void setDecimalLongitude(Double decimalLongitude) { this.decimalLongitude = decimalLongitude; updateLocation(); } /** * * @param id Set the id */ public void setId(Long id) { this.id = id; } @Enumerated(value = EnumType.STRING) public TypeStatus getTypeStatus() { return typeStatus; } public void setTypeStatus(TypeStatus typeStatus) { this.typeStatus = typeStatus; } @Enumerated(value = EnumType.STRING) public TypeDesignationType getTypeDesignationType() { return typeDesignationType; } public void setTypeDesignationType(TypeDesignationType typeDesignationType) { this.typeDesignationType = typeDesignationType; } @Size(max = 255) public String getTypeDesignatedBy() { return typeDesignatedBy; } public void setTypeDesignatedBy(String typeDesignatedBy) { this.typeDesignatedBy = typeDesignatedBy; } @Size(max = 255) public String getScientificName() { return scientificName; } public void setScientificName(String scientificName) { this.scientificName = scientificName; } @Enumerated(value = EnumType.STRING) public Rank getTaxonRank() { return taxonRank; } public void setTaxonRank(Rank taxonRank) { this.taxonRank = taxonRank; } @Size(max = 255) public String getBibliographicCitation() { return bibliographicCitation; } public void setBibliographicCitation(String bibliographicCitation) { this.bibliographicCitation = bibliographicCitation; } @Size(max = 255) public String getInstitutionCode() { return institutionCode; } public void setInstitutionCode(String institutionCode) { this.institutionCode = institutionCode; } @Size(max = 255) public String getCollectionCode() { return collectionCode; } public void setCollectionCode(String collectionCode) { this.collectionCode = collectionCode; } @Size(max = 255) public String getCatalogNumber() { return catalogNumber; } public void setCatalogNumber(String catalogNumber) { this.catalogNumber = catalogNumber; } @Lob public String getLocality() { return locality; } public void setLocality(String locality) { this.locality = locality; } @Enumerated(value = EnumType.STRING) public Sex getSex() { return sex; } public void setSex(Sex sex) { this.sex = sex; } @Size(max = 255) public String getRecordedBy() { return recordedBy; } public void setRecordedBy(String recordedBy) { this.recordedBy = recordedBy; } @Size(max = 255) public String getSource() { return source; } public void setSource(String source) { this.source = source; } @Size(max = 255) public String getVerbatimEventDate() { return verbatimEventDate; } public void setVerbatimEventDate(String verbatimEventDate) { this.verbatimEventDate = verbatimEventDate; } @Size(max = 255) public String getVerbatimLabel() { return verbatimLabel; } public void setVerbatimLabel(String verbatimLabel) { this.verbatimLabel = verbatimLabel; } @Size(max = 255) public String getVerbatimLongitude() { return verbatimLongitude; } public void setVerbatimLongitude(String verbatimLongitude) { this.verbatimLongitude = verbatimLongitude; } @Size(max = 255) public String getVerbatimLatitude() { return verbatimLatitude; } public void setVerbatimLatitude(String verbatimLatitude) { this.verbatimLatitude = verbatimLatitude; } @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "Taxon_TypeAndSpecimen", joinColumns = {@JoinColumn(name = "typesAndSpecimens_id")}, inverseJoinColumns = {@JoinColumn(name = "Taxon_id")}) @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE }) @JsonSerialize(contentUsing = TaxonSerializer.class) public Set<Taxon> getTaxa() { return taxa; } @JsonDeserialize(contentUsing = TaxonDeserializer.class) public void setTaxa(Set<Taxon> taxa) { this.taxa = taxa; } @Transient @JsonIgnore public final String getClassName() { return "TypeAndSpecimen"; } @OneToMany(fetch = FetchType.LAZY, orphanRemoval = true) @JoinColumn(name = "annotatedObjId") @Where(clause = "annotatedObjType = 'TypeAndSpecimen'") @Cascade({ CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.DELETE }) @JsonIgnore public Set<Annotation> getAnnotations() { return annotations; } /** * @param annotations * the annotations to set */ public void setAnnotations(Set<Annotation> annotations) { this.annotations = annotations; } private void updateLocation() { if(this.decimalLatitude != null && this.decimalLongitude != null) { GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); this.location = geometryFactory.createPoint(new Coordinate(this.decimalLongitude, this.decimalLatitude)); } else { this.location = null; } } @Override public String toString() { StringBuffer stringBuffer = new StringBuffer(); if(institutionCode != null) { stringBuffer.append(institutionCode); } if(catalogNumber != null) { stringBuffer.append(" " + catalogNumber); } if(collectionCode != null) { stringBuffer.append(" " + collectionCode); } return stringBuffer.toString(); } @Override @Transient @JsonIgnore public String getDocumentId() { return getClassName() + "_" + getId(); } protected void addField(SolrInputDocument sid, String name, Serializable value) { if(value != null && !value.toString().isEmpty()) { sid.addField(name, value); } } @Override public SolrInputDocument toSolrInputDocument() { SolrInputDocument sid = new SolrInputDocument(); sid.addField("id", getDocumentId()); sid.addField("base.id_l", getId()); sid.addField("base.class_searchable_b", false); sid.addField("base.class_s", getClass().getName()); sid.addField("searchable.label_sort", toString()); StringBuilder summary = new StringBuilder().append(getCatalogNumber()).append(" ") .append(getCollectionCode()).append(" ").append(getInstitutionCode()).append(" ").append(getLocality()) .append(" ").append(getRecordedBy()).append(" ").append(getScientificName()).append(" ").append(getSex()) .append(" ").append(getTypeDesignatedBy()).append(" ").append(getVerbatimEventDate()).append(" ").append(getVerbatimLabel()) .append(" ").append(getVerbatimLatitude()).append(" ").append(getVerbatimLongitude()).append(" ").append(getTaxonRank()) .append(" ").append(getTypeDesignationType()).append(" ").append(getTypeStatus()); if(!getTaxa().isEmpty()) { boolean first = true; for(Taxon t : getTaxa()) { addField(sid,"taxon.family_ss", t.getFamily()); addField(sid,"taxon.subfamily_ss", t.getSubfamily()); addField(sid,"taxon.subtribe_ss", t.getSubtribe()); addField(sid,"taxon.tribe_ss", t.getTribe()); addField(sid,"taxon.genus_ss", t.getGenus()); if(first) { //addField(sid,"taxon.class_s", t.getClazz()); //addField(sid,"taxon.kingdom_s", t.getKingdom()); //addField(sid,"taxon.phylum_s", getTaxon().getPhylum()); addField(sid,"taxon.order_s", t.getOrder()); addField(sid,"taxon.subgenus_s", t.getSubgenus()); } summary.append(" ").append(t.getClazz()) .append(" ").append(t.getClazz()) .append(" ").append(t.getFamily()) .append(" ").append(t.getGenus()) .append(" ").append(t.getKingdom()) .append(" ").append(t.getOrder()) .append(" ").append(t.getPhylum()) .append(" ").append(t.getSubfamily()) .append(" ").append(t.getSubgenus()) .append(" ").append(t.getSubtribe()) .append(" ").append(t.getTribe()); first = false; } } if(getAuthority() != null) { sid.addField("base.authority_s", getAuthority().getIdentifier()); summary.append(" ").append(getAuthority().getIdentifier()); } if (getLocation() != null) { try { WKTWriter wktWriter = new WKTWriter(); sid.addField("geo", wktWriter.write(getLocation())); } catch (Exception e) { logger.error(e.getLocalizedMessage()); } } sid.addField("searchable.solrsummary_t",summary.toString()); return sid; } }