package org.gbif.checklistbank.neo; import org.gbif.api.model.checklistbank.NameUsage; import org.gbif.api.vocabulary.Origin; import org.gbif.api.vocabulary.Rank; import org.gbif.api.vocabulary.TaxonomicStatus; import org.gbif.checklistbank.logging.LogContext; import org.gbif.checklistbank.cli.model.NameUsageNode; import org.gbif.checklistbank.cli.model.RankedName; import org.gbif.checklistbank.neo.traverse.Traversals; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.UUID; import javax.annotation.Nullable; import com.google.common.collect.Lists; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.ResourceIterator; import org.neo4j.helpers.collection.Iterables; import org.neo4j.helpers.collection.Iterators; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * */ public class ImportDb { private static final Logger LOG = LoggerFactory.getLogger(ImportDb.class); protected final UUID datasetKey; protected final UsageDao dao; public ImportDb(UUID datasetKey, UsageDao dao) { this.datasetKey = datasetKey; this.dao = dao; LogContext.startDataset(datasetKey); } /** * @return the single matching node with the taxonID or null */ protected Node nodeByTaxonId(String taxonID) { // try { return Iterators.singleOrNull(dao.getNeo().findNodes(Labels.TAXON, NeoProperties.TAXON_ID, taxonID)); // } catch (NoSuchElementException e) { // throw new NotUniqueException(taxonID, "TaxonID not unique: " + taxonID); // } } /** * @return the single matching node with the canonical name or null */ protected Node nodeByCanonical(String canonical) throws NotUniqueException { try { return Iterators .singleOrNull(dao.getNeo().findNodes(Labels.TAXON, NeoProperties.CANONICAL_NAME, canonical)); } catch (NoSuchElementException e) { throw new NotUniqueException(canonical, "Canonical name not unique: " + canonical); } } protected Collection<Node> nodesByCanonical(String canonical) { return Iterators .asCollection(dao.getNeo().findNodes(Labels.TAXON, NeoProperties.CANONICAL_NAME, canonical)); } protected List<Node> nodesByCanonicalAndRank(String canonical, Rank rank) { List<Node> matching = filterByRank(dao.getNeo().findNodes(Labels.TAXON, NeoProperties.CANONICAL_NAME, canonical), rank); if (matching.size() > 10) { LOG.warn("There are {} matches for the {} {}. This might indicate we are not dealing with a proper checklist", matching.size(), rank, canonical); } return matching; } private List<Node> filterByRank(ResourceIterator<Node> nodes, Rank rank) { List<Node> matchingRanks = Lists.newArrayList(); while (nodes.hasNext()) { Node n = nodes.next(); if (rank == null || n.getProperty(NeoProperties.RANK, rank.ordinal()).equals(rank.ordinal())) { matchingRanks.add(n); } } return matchingRanks; } /** * @return the single matching node with the scientific name or null */ protected Node nodeBySciname(String sciname) throws NotUniqueException { try { return Iterators .singleOrNull(dao.getNeo().findNodes(Labels.TAXON, NeoProperties.SCIENTIFIC_NAME, sciname)); } catch (NoSuchElementException e) { throw new NotUniqueException(sciname, "Scientific name not unique: " + sciname); } } protected NameUsageNode create(Origin origin, String sciname, Rank rank, TaxonomicStatus status, boolean isRoot) { return create(origin, sciname, rank, status, isRoot, null, null); } protected NameUsageNode create(Origin origin, String sciname, Rank rank, TaxonomicStatus status, boolean isRoot, @Nullable String taxonID, @Nullable String remark) { NameUsage u = new NameUsage(); u.setScientificName(sciname); //TODO: parse name??? u.setCanonicalName(sciname); u.setRank(rank); u.setOrigin(origin); u.setTaxonomicStatus(status); u.setTaxonID(taxonID); u.setRemarks(remark); return create(u, isRoot); } protected NameUsageNode create(NameUsage u, boolean isRoot) { Node n = dao.createTaxon(); if (u.getTaxonomicStatus() != null && u.getTaxonomicStatus().isSynonym()) { n.addLabel(Labels.SYNONYM); } if (isRoot) { n.addLabel(Labels.ROOT); } NameUsageNode nn = new NameUsageNode(n, u, true); dao.store(nn, true); return nn; } protected boolean matchesClassification(Node n, List<RankedName> classification) { Iterator<RankedName> clIter = classification.listIterator(); Iterator<Node> nodeIter = Traversals.PARENTS.traverse(n).nodes().iterator(); while (clIter.hasNext()) { if (!nodeIter.hasNext()) { return false; } RankedName rn1 = clIter.next(); RankedName rn2 = dao.readRankedName(nodeIter.next()); if (rn1.rank != rn2.rank || !rn1.name.equals(rn2.name)) { return false; } } return !nodeIter.hasNext(); } /** * @return the last parent or the node itself if no parent exists */ protected RankedName getDirectParent(Node n) { Node p = Iterables.lastOrNull(Traversals.PARENTS.traverse(n).nodes()); return dao.readRankedName(p != null ? p : n); } protected Node getLinneanRankParent(Node n) { return Iterables.firstOrNull(Traversals.LINNEAN_PARENTS.traverse(n).nodes()); } public UUID getDatasetKey() { return datasetKey; } }