Commit 3b99eddf authored by Matija Obreza's avatar Matija Obreza

New taxonomy

parent 78fdb4b0
......@@ -21,7 +21,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.Taxonomy;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.FaoInstitute;
import org.hibernate.search.bridge.FieldBridge;
......@@ -51,7 +51,7 @@ public class AccessionBridge implements FieldBridge {
sd.append(countryOfOrigin.getName());
}
Taxonomy taxonomy = accession.getTaxonomy();
Taxonomy2 taxonomy = accession.getTaxonomy();
if (taxonomy != null) {
sd.append(taxonomy.getTaxonName());
}
......
......@@ -135,18 +135,14 @@ public class Accession extends VersionedAuditedModel {
this.accessionName = accessionName;
}
public Taxonomy getTaxonomy() {
public Taxonomy getTaxonomy1() {
return this.taxonomy;
}
public Taxonomy2 getTaxonomy2() {
public Taxonomy2 getTaxonomy() {
return this.taxonomy2;
}
public void setTaxonomy(final Taxonomy taxonomy) {
this.taxonomy = taxonomy;
}
public String getAcquisitionSource() {
return this.acquisitionSource;
}
......@@ -252,7 +248,7 @@ public class Accession extends VersionedAuditedModel {
this.taxSpecies = taxSpecies;
}
public void setTaxonomy2(Taxonomy2 taxonomy2) {
public void setTaxonomy(Taxonomy2 taxonomy2) {
this.taxonomy2 = taxonomy2;
}
......
......@@ -20,6 +20,7 @@ import java.text.MessageFormat;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
......@@ -49,6 +50,14 @@ public class Taxonomy2 extends GlobalVersionedAuditedModel {
@Column(nullable = true, length = 100)
private String subtAuthor;
@Column(nullable = false)
@Lob
private String taxonName;
private long taxGenus;
private Long taxSpecies;
// @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = "taxonomy")
// private List<CropTaxonomy> cropTaxonomies;
......@@ -80,6 +89,11 @@ public class Taxonomy2 extends GlobalVersionedAuditedModel {
return sb.toString();
}
public void setTaxonName(String taxonName) {
// Ignore what they provide
taxonName = getTaxonName();
}
// public List<CropTaxonomy> getCropTaxonomies() {
// return cropTaxonomies;
// }
......@@ -88,13 +102,53 @@ public class Taxonomy2 extends GlobalVersionedAuditedModel {
// this.cropTaxonomies = cropTaxonomies;
// }
@Override
public String toString() {
return MessageFormat.format("Tax id={0} taxonName=", id, getTaxonName());
public String getSpAuthor() {
return spAuthor;
}
public void setSpAuthor(String spAuthor) {
this.spAuthor = spAuthor;
}
public String getSubtaxa() {
return subtaxa;
}
public void setSubtaxa(String subtaxa) {
this.subtaxa = subtaxa;
}
public String getSubtAuthor() {
return subtAuthor;
}
public void setSubtAuthor(String subtAuthor) {
this.subtAuthor = subtAuthor;
}
public boolean sameAs(Taxonomy2 taxonomy) {
return taxonomy == null ? false : taxonomy.getId().equals(id);
}
public long getTaxGenus() {
return this.taxGenus;
}
public void setTaxGenus(long taxGenus) {
this.taxGenus = taxGenus;
}
public Long getTaxSpecies() {
return this.taxSpecies;
}
public void setTaxSpecies(Long taxSpecies) {
this.taxSpecies = taxSpecies;
}
@Override
public String toString() {
return MessageFormat.format("Tax id={0} taxonName=", id, getTaxonName());
}
}
......@@ -24,6 +24,7 @@ import javax.persistence.Table;
import org.genesys2.server.model.BusinessModel;
import org.genesys2.server.model.genesys.Taxonomy;
// TODO FIXME Need to link to {@link Taxonomy2}
@Entity
@Table(name = "croptaxonomy")
public class CropTaxonomy extends BusinessModel {
......
......@@ -87,6 +87,7 @@ public class FaoInstitute extends BusinessModel implements GeoReferencedEntity,
private Double latitude;
private Double longitude;
private Double elevation;
private boolean uniqueAcceNumbs;
public FaoInstitute() {
}
......@@ -210,4 +211,12 @@ public class FaoInstitute extends BusinessModel implements GeoReferencedEntity,
public void setSettings(Map<String, FaoInstituteSetting> settings) {
this.settings = settings;
}
public boolean hasUniqueAcceNumbs() {
return this.uniqueAcceNumbs;
}
public void setUniqueAcceNumbs(boolean uniqueAcceNumbs) {
this.uniqueAcceNumbs = uniqueAcceNumbs;
}
}
......@@ -96,8 +96,7 @@ public interface AccessionRepository extends JpaRepository<Accession, Long> {
@Query("select a from Accession a where a.taxonomy in ( ?1 )")
Page<Accession> findByTaxonomy(Collection<Taxonomy> taxonomies, Pageable pageable);
// Accession findByInstituteCodeAndAccessionName(String holdingInstitute,
// String accessionName);
Accession findByInstituteCodeAndAccessionName(String instCode, String acceNumb);
Accession findByInstituteCodeAndAccessionNameAndGenus(String holdingInstitute, String accessionName, String genus);
......
/**
* Copyright 2014 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package org.genesys2.server.persistence.domain;
import java.util.List;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
public interface Taxonomy2Repository extends JpaRepository<Taxonomy2, Long> {
@Query("select distinct t.genus from Taxonomy2 t where t.genus like ?1")
List<String> autocompleteGenus(String term, Pageable page);
@Query("select distinct t.taxonName from Taxonomy2 t where t.taxonName like ?1")
List<String> autocompleteTaxonomy(String term, Pageable page);
@Query("select t from Taxonomy2 t where t.genus=?1 and t.species=?2 and t.spAuthor=?3 and t.subtaxa=?4 and t.subtAuthor=?5")
Taxonomy2 findOne(String genus, String species, String spAuthor, String subtaxa, String subtAuthor);
}
......@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.service.impl.RESTApiException;
import org.genesys2.server.servlet.controller.rest.model.AccessionJson;
import org.genesys2.server.servlet.controller.rest.model.AccessionNamesJson;
......@@ -27,7 +28,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
public interface BatchRESTService {
boolean upsertAccessionData(FaoInstitute institute, Map<AccessionJson, ObjectNode> batch);
boolean upsertAccessionData(FaoInstitute institute, Map<AccessionJson, ObjectNode> batch) throws RESTApiException;
void upsertAccessionNames(FaoInstitute institute, List<AccessionNamesJson> batch);
......
......@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Locale;
import org.genesys2.server.model.genesys.Taxonomy;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.model.impl.CropRule;
import org.genesys2.server.model.impl.CropTaxonomy;
......@@ -36,6 +37,8 @@ public interface CropService {
List<Crop> getCrops(Taxonomy taxonomy);
List<Crop> getCrops(Taxonomy2 taxonomy2);
void rebuildTaxonomies();
Page<CropTaxonomy> getCropTaxonomies(Crop crop, Pageable pageable);
......
......@@ -95,7 +95,7 @@ public interface GenesysService {
Accession getAccession(AccessionIdentifier3 aid3);
Accession getAccession(String instCode, String genus, String acceNumb);
Accession getAccession(String instCode, String acceNumb, String genus);
Page<Object[]> statisticsGenusByInstitute(FaoInstitute faoInstitute, Pageable pageable);
......@@ -163,4 +163,13 @@ public interface GenesysService {
long countAll();
/**
* For institutes with {@link FaoInstitute#uniqueAcceNumbs}
*
* @param instCode
* @param acceNumb
* @return the 1 accession
*/
Accession getAccession(String instCode, String acceNumb);
}
......@@ -19,6 +19,7 @@ package org.genesys2.server.service;
import java.util.List;
import org.genesys2.server.model.genesys.Taxonomy;
import org.genesys2.server.model.genesys.Taxonomy2;
public interface TaxonomyService {
......@@ -31,4 +32,10 @@ public interface TaxonomyService {
List<String> autocompleteTaxonomy(String term);
long getTaxonomy2Id(String genus);
long getTaxonomy2Id(String genus, String species);
Taxonomy2 ensureTaxonomy2(String genus, String species, String spAuthor, String subtaxa, String subtAuthor);
}
......@@ -36,7 +36,7 @@ import org.genesys2.server.model.genesys.AccessionBreeding;
import org.genesys2.server.model.genesys.AccessionCollect;
import org.genesys2.server.model.genesys.AccessionExchange;
import org.genesys2.server.model.genesys.AccessionGeo;
import org.genesys2.server.model.genesys.Taxonomy;
import org.genesys2.server.model.genesys.Taxonomy2;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.service.BatchRESTService;
......@@ -81,8 +81,11 @@ public class BatchRESTServiceImpl implements BatchRESTService {
@Override
@Transactional
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#institute, 'WRITE') or hasPermission(#institute, 'CREATE')")
public boolean upsertAccessionData(FaoInstitute institute, Map<AccessionJson, ObjectNode> batch) {
public boolean upsertAccessionData(FaoInstitute institute, Map<AccessionJson, ObjectNode> batch) throws RESTApiException {
LOG.info("Batch processing " + batch.size() + " entries for " + institute);
boolean useUniqueAcceNumbs = institute.hasUniqueAcceNumbs();
List<Accession> toSave = new ArrayList<Accession>();
List<AccessionCollect> toSaveColl = new ArrayList<AccessionCollect>();
List<AccessionGeo> toSaveGeo = new ArrayList<AccessionGeo>();
......@@ -102,94 +105,39 @@ public class BatchRESTServiceImpl implements BatchRESTService {
throw new RuntimeException("Accession does not belong to instCode=" + institute.getCode() + " acn=" + dataJson);
}
Accession accession = genesysService.getAccession(dataJson.instCode, dataJson.genus, dataJson.acceNumb);
Accession accession = null;
if (useUniqueAcceNumbs)
accession = genesysService.getAccession(dataJson.instCode, dataJson.acceNumb);
else
accession = genesysService.getAccession(dataJson.instCode, dataJson.acceNumb, dataJson.genus);
boolean updated = false;
ObjectNode accnJson = batch.get(dataJson);
if (accession == null) {
LOG.warn("New accession " + dataJson);
accession = new Accession();
accession.setInstituteCode(dataJson.instCode);
accession.setInstitute(institute);
accession.setGenus(dataJson.genus);
accession.setAccessionName(dataJson.acceNumb);
updated = true;
}
ObjectNode accnJson = batch.get(dataJson);
JsonNode value = accnJson.get("orgCty");
if (value != null) {
String orgCty = value.textValue();
if (!StringUtils.equals(orgCty, accession.getOrigin())) {
Country country = geoService.getCountry(orgCty);
accession.setOrigin(orgCty);
accession.setCountryOfOrigin(country);
updated = true;
}
}
/* Allow updating AcceNumb */
value = accnJson.get("newAcceNumb");
if (value != null) {
String newAcceNumb = value.isNull() ? null : value.textValue();
if (!StringUtils.equals(newAcceNumb, accession.getAccessionName())) {
accession.setAccessionName(newAcceNumb);
updated = true;
}
}
/* Allow updating Genus */
value = accnJson.get("newGenus");
if (value != null) {
String newGenus = value.isNull() ? null : value.textValue();
if (!StringUtils.equals(newGenus, accession.getGenus())) {
accession.setGenus(newGenus);
updated = true;
// Need to do taxonomy
String species = null;
if (accession.getTaxonomy() != null)
species = accession.getTaxonomy().getSpecies();
value = accnJson.get("species");
if (value != null) {
species = value.isNull() ? null : value.textValue();
}
Taxonomy taxonomy = taxonomyService.ensureTaxonomy(accession.getGenus(), species);
if (!taxonomy.sameAs(accession.getTaxonomy())) {
accession.setTaxonomy(taxonomy);
}
if (accnJson.get("genus") == null || accnJson.get("newGenus") == null) {
throw new RESTApiException("Cannot create new accession without specifying genus");
}
}
value = accnJson.get("species");
if (value != null) {
String species = value.isNull() ? null : value.textValue();
Taxonomy taxonomy = taxonomyService.ensureTaxonomy(accession.getGenus(), species);
if (!taxonomy.sameAs(accession.getTaxonomy())) {
accession.setTaxonomy(taxonomy);
updated = true;
}
updated = true;
}
value = accnJson.get("uuid");
if (value != null) {
String uuid = value.isNull() ? null : value.textValue();
if (!StringUtils.equals(uuid, accession.getUuid())) {
if (uuid != null) {
// Throws a runtime exception if format is invalid
UUID.fromString(uuid);
}
accession.setUuid(uuid);
updated = true;
}
}
updated |= updateAcceNumb(accession, accnJson.get("newAcceNumb"));
updated |= updateTaxonomy(accession, accnJson);
updated |= updateOrgCty(accession, accnJson.get("orgCty"));
updated |= updateUuid(accession, accnJson.get("uuid"));
value = accnJson.get("acqDate");
// TODO Move other setters to methods
JsonNode value = accnJson.get("acqDate");
if (value != null) {
String acqDate = value.isNull() ? null : value.textValue();
if (!StringUtils.equals(acqDate, accession.getAcquisitionDate())) {
......@@ -417,6 +365,128 @@ public class BatchRESTServiceImpl implements BatchRESTService {
return toSave.size() > 0 || toSaveColl.size() > 0 || toSaveGeo.size() > 0 || toSaveBreed.size() > 0 || toSaveExch.size() > 0;
}
private boolean updateAcceNumb(Accession accession, JsonNode value) throws RESTApiDataTypeException, RESTApiValueException {
if (value != null) {
if (!value.isTextual()) {
throw new RESTApiDataTypeException("newAcceNumb must be a String");
}
if (value.isNull()) {
throw new RESTApiValueException("newAcceNumb cannot be null");
}
String newAcceNumb=value.textValue();
if (!StringUtils.equals(newAcceNumb, accession.getAccessionName())) {
accession.setAccessionName(newAcceNumb);
return true;
}
}
return false;
}
private boolean updateOrgCty(Accession accession, JsonNode value) throws RESTApiDataTypeException, RESTApiValueException {
if (value != null) {
if (!value.isNull() && !value.isTextual())
throw new RESTApiDataTypeException("orgCty must be a String");
String orgCty = value.textValue();
if (!StringUtils.equals(orgCty, accession.getOrigin())) {
Country country = null;
if (orgCty != null) {
country = geoService.getCountry(orgCty);
if (country == null)
throw new RESTApiValueException("No country with ISO3 code: " + orgCty);
}
accession.setOrigin(orgCty);
accession.setCountryOfOrigin(country);
return true;
}
}
return false;
}
private boolean updateUuid(Accession accession, JsonNode value) throws RESTApiValueException {
if (value != null) {
String uuid = value.isNull() ? null : value.textValue();
if (!StringUtils.equals(uuid, accession.getUuid())) {
if (uuid != null) {
try {
// Throws a runtime exception if format is invalid
UUID.fromString(uuid);
} catch (RuntimeException e) {
throw new RESTApiValueException("UUID " + uuid + " is not in valid format: " + e.getMessage());
}
}
accession.setUuid(uuid);
return true;
}
}
// No change
return false;
}
/**
* Inspect incoming JSON and change taxonomy if required
*
* @param accession
* @param accnJson
*
* @return true if taxonomy was modified
* @throws RESTApiException
*/
private boolean updateTaxonomy(Accession accession, JsonNode accnJson) throws RESTApiException {
boolean updated = false;
// Do not persist this one, temporary use
Taxonomy2 current = accession.getTaxonomy();
if (current == null) {
current = new Taxonomy2();
}
// Load JSON values into "current"
current.setGenus(StringUtils.defaultIfBlank(stringIfProvided(accnJson.get("genus")), current.getGenus()));
current.setGenus(StringUtils.defaultIfBlank(stringIfProvided(accnJson.get("newGenus")), current.getGenus()));
current.setSpecies(StringUtils.defaultIfBlank(stringIfProvided(accnJson.get("species")), current.getSpecies()));
current.setSpAuthor(StringUtils.defaultIfBlank(stringIfProvided(accnJson.get("spauthor")), current.getSpAuthor()));
current.setSubtaxa(StringUtils.defaultIfBlank(stringIfProvided(accnJson.get("subtaxa")), current.getSubtaxa()));
current.setSubtAuthor(StringUtils.defaultIfBlank(stringIfProvided(accnJson.get("subtauthor")), current.getSubtAuthor()));
Taxonomy2 ensuredTaxonomy = null;
if (current.getId() == null
|| !((ensuredTaxonomy = taxonomyService.ensureTaxonomy2(current.getGenus(), current.getSpecies(), current.getSpAuthor(), current.getSubtaxa(),
current.getSubtAuthor())).sameAs(current))) {
accession.setTaxonomy(ensuredTaxonomy);
accession.setTaxGenus(ensuredTaxonomy.getTaxGenus());
accession.setTaxSpecies(ensuredTaxonomy.getTaxSpecies());
updated = true;
}
return updated;
}
/**
* Return
*
* @param jsonNode
* @return
* @throws RESTApiDataTypeException
*/
private String stringIfProvided(JsonNode jsonNode) throws RESTApiException {
if (jsonNode != null) {
if (!jsonNode.isTextual()) {
// We expect a String node
throw new RESTApiDataTypeException("Not a String");
}
if (StringUtils.isBlank(jsonNode.textValue())) {
throw new RESTApiValueException("Value cannot be a blank String");
}
return StringUtils.defaultIfBlank(jsonNode.textValue(), null);
}
return null;
}
private String arrayToString(ArrayNode arr) {
if (arr == null || arr.isNull())
return null;
......@@ -514,7 +584,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
List<AccessionAlias> toRemove = new ArrayList<AccessionAlias>();
for (AccessionNamesJson dataJson : batch) {
Accession accession = genesysService.getAccession(institute.getCode(), dataJson.genus, dataJson.acceNumb);
Accession accession = genesysService.getAccession(institute.getCode(), dataJson.acceNumb, dataJson.genus);
if (accession == null) {
LOG.warn("No such accession " + dataJson);
continue;
......@@ -599,7 +669,7 @@ public class BatchRESTServiceImpl implements BatchRESTService {
throw new RuntimeException("Accession does not belong to instCode=" + institute.getCode() + " acn=" + dataJson);
}
Accession accession = genesysService.getAccession(dataJson.instCode, dataJson.genus, dataJson.acceNumb);
Accession accession = genesysService.getAccession(dataJson.instCode, dataJson.acceNumb, dataJson.genus);
if (accession != null) {
toDelete.add(accession);
}
......
......@@ -26,6 +26,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.genesys2.server.model.genesys.Taxonomy;