/*
* 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.job.dwc.taxon;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.emonocot.api.ReferenceService;
import org.emonocot.job.dwc.exception.NoIdentifierException;
import org.emonocot.job.dwc.read.DarwinCoreProcessor;
import org.emonocot.model.Annotation;
import org.emonocot.model.Reference;
import org.emonocot.model.Taxon;
import org.emonocot.model.constants.AnnotationCode;
import org.emonocot.model.constants.AnnotationType;
import org.emonocot.model.constants.RecordType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.ChunkListener;
import org.springframework.batch.core.ItemWriteListener;
import org.springframework.beans.factory.annotation.Autowired;
/**
*
* @author ben
*
*/
public class Processor extends DarwinCoreProcessor<Taxon> implements ChunkListener, ItemWriteListener<Taxon> {
private Set<TaxonRelationship> taxonRelationships = new HashSet<TaxonRelationship>();
private Map<String, Reference> boundReferences = new HashMap<String, Reference>();
private Map<String, Taxon> boundTaxa = new HashMap<String,Taxon>();
private Logger logger = LoggerFactory.getLogger(Processor.class);
private ReferenceService referenceService;
@Autowired
public void setReferenceService(ReferenceService referenceService) {
this.referenceService = referenceService;
}
/**
* @param t
* a taxon object
* @throws Exception
* if something goes wrong
* @return Taxon a taxon object
*/
public Taxon doProcess(Taxon t) throws Exception {
logger.info("Processing " + t.getIdentifier());
if (t.getIdentifier() == null) {
throw new NoIdentifierException(t);
}
/**
* replace references with persisted objects or new ones
*/
t.setNameAccordingTo(resolveReference(t.getNameAccordingTo()));
t.setNamePublishedIn(resolveReference(t.getNamePublishedIn()));
Taxon persisted = getTaxonService().find(t.getIdentifier());
if (persisted == null) {
// Taxon is new
bindRelationships(t,t);
validate(t);
Annotation annotation = createAnnotation(t, RecordType.Taxon, AnnotationCode.Create, AnnotationType.Info);
t.getAnnotations().add(annotation);
t.setAuthority(getSource());
logger.info("Adding taxon " + t);
return t;
} else if(boundTaxa.containsKey(t.getIdentifier())) {
logger.error(t.getIdentifier() + " was found earlier in this archive");
createAnnotation(boundTaxa.get(t.getIdentifier()), RecordType.Taxon, AnnotationCode.AlreadyProcessed, AnnotationType.Warn);
return null;
} else {
checkAuthority(RecordType.Taxon, t, persisted.getAuthority());
if (skipUnmodified
&& ((persisted.getModified() != null && t.getModified() != null) && !persisted
.getModified().isBefore(t.getModified()))) {
bindTaxon(persisted);
replaceAnnotation(persisted, AnnotationType.Info,
AnnotationCode.Skipped);
} else {
bindRelationships(t, persisted);
persisted.setAccessRights(t.getAccessRights());
persisted.setCreated(t.getCreated());
persisted.setLicense(t.getLicense());
persisted.setModified(t.getModified());
persisted.setRights(t.getRights());
persisted.setRightsHolder(t.getRightsHolder());
persisted
.setBibliographicCitation(t.getBibliographicCitation());
persisted.setClazz(t.getClazz());
persisted.setFamily(t.getFamily());
persisted.setGenus(t.getGenus());
persisted.setInfraspecificEpithet(t.getInfraspecificEpithet());
persisted.setKingdom(t.getKingdom());
persisted.setNameAccordingTo(t.getNameAccordingTo());
persisted.setNamePublishedIn(t.getNamePublishedIn());
persisted
.setNamePublishedInString(t.getNamePublishedInString());
persisted.setNamePublishedInYear(t.getNamePublishedInYear());
persisted.setNomenclaturalCode(t.getNomenclaturalCode());
persisted.setNomenclaturalStatus(t.getNomenclaturalStatus());
persisted.setOrder(t.getOrder());
persisted.setPhylum(t.getPhylum());
persisted.setScientificName(t.getScientificName());
persisted.setScientificNameAuthorship(t
.getScientificNameAuthorship());
persisted.setScientificNameID(t.getScientificNameID());
persisted.setSource(t.getSource());
persisted.setSpecificEpithet(t.getSpecificEpithet());
persisted.setSubfamily(t.getSubfamily());
persisted.setSubgenus(t.getSubgenus());
persisted.setSubtribe(t.getSubtribe());
persisted.setTaxonomicStatus(t.getTaxonomicStatus());
persisted.setTaxonRank(t.getTaxonRank());
persisted.setTaxonRemarks(t.getTaxonRemarks());
persisted.setTribe(t.getTribe());
persisted.setTaxonRank(t.getTaxonRank());
persisted.setUri(t.getUri());
validate(t);
replaceAnnotation(persisted, AnnotationType.Info,
AnnotationCode.Update);
}
logger.info("Overwriting taxon " + persisted);
return persisted;
}
}
private void bindTaxon(Taxon persisted) {
boundTaxa.put(persisted.getIdentifier(), persisted);
}
private void bindRelationships(Taxon t, Taxon u) {
bindTaxon(u);
if(t.getParentNameUsage() != null) {
this.taxonRelationships.add(new TaxonRelationship(u, TaxonRelationshipType.parent, t.getParentNameUsage().getIdentifier(), t.getParentNameUsage().getScientificName()));
}
if(t.getAcceptedNameUsage() != null) {
this.taxonRelationships.add(new TaxonRelationship(u, TaxonRelationshipType.accepted, t.getAcceptedNameUsage().getIdentifier(), t.getAcceptedNameUsage().getScientificName()));
}
if(t.getOriginalNameUsage() != null) {
this.taxonRelationships.add(new TaxonRelationship(u, TaxonRelationshipType.original, t.getOriginalNameUsage().getIdentifier(), t.getOriginalNameUsage().getScientificName()));
}
u.setParentNameUsage(null);
u.setAcceptedNameUsage(null);
u.setOriginalNameUsage(null);
}
@Override
public void beforeChunk() {
boundTaxa = new HashMap<String,Taxon>();
taxonRelationships = new HashSet<TaxonRelationship>();
boundReferences = new HashMap<String, Reference>();
}
@Override
public void afterChunk() {}
private Taxon resolveTaxon(String identifier, String scientificName) {
if (boundTaxa.containsKey(identifier)) {
logger.info("Found taxon " + scientificName + " with identifier " + identifier + " from cache returning taxon with id " + boundTaxa.get(identifier).getId());
return boundTaxa.get(identifier);
} else {
Taxon taxon = getTaxonService().find(identifier);
if (taxon == null) {
taxon = new Taxon();
Annotation annotation = createAnnotation(taxon, RecordType.Taxon,
AnnotationCode.Create, AnnotationType.Info);
taxon.getAnnotations().add(annotation);
taxon.setAuthority(getSource());
taxon.setIdentifier(identifier);
taxon.setScientificName(scientificName);
logger.info("Didn't find taxon " + scientificName + " with identifier " + identifier + " from service returning new taxon");
bindTaxon(taxon);
} else {
logger.info("Found taxon " + scientificName + "with identifier " + identifier + " from service returning taxon with id " + taxon.getId());
bindTaxon(taxon);
}
return taxon;
}
}
/**
*
* @param object
* Set the text content object
* @param value
* the source of the reference to resolve
*/
private Reference resolveReference(Reference reference) {
if (reference == null) {
return null;
} else {
String identifier = reference.getIdentifier();
if (identifier == null || identifier.trim().length() == 0) {
// there is not citation identifier
return null;
} else {
if (boundReferences.containsKey(identifier)) {
return boundReferences.get(identifier);
} else {
Reference r = referenceService.find(identifier);
if (r == null) {
r = new Reference();
r.setIdentifier(identifier);
Annotation annotation = super.createAnnotation(r,
RecordType.Reference, AnnotationCode.Create,
AnnotationType.Info);
r.getAnnotations().add(annotation);
r.setAuthority(getSource());
}
boundReferences.put(identifier, r);
return r;
}
}
}
}
@Override
public void beforeWrite(List<? extends Taxon> items) {
logger.info("Before Write");
for (TaxonRelationship taxonRelationship : taxonRelationships) {
Taxon to = resolveTaxon(taxonRelationship.getToIdentifier(), taxonRelationship.getToScientificName());
Taxon from = taxonRelationship.getFrom();
switch(taxonRelationship.getTerm()) {
case original:
from.setOriginalNameUsage(to);
break;
case accepted:
from.setAcceptedNameUsage(to);
break;
case parent:
from.setParentNameUsage(to);
break;
}
}
}
@Override
public void afterWrite(List<? extends Taxon> items) {
}
@Override
public void onWriteError(Exception exception, List<? extends Taxon> items) {
}
}