2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
9 package eu
.etaxonomy
.cdm
.io
.wfo
.out
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Iterator
;
14 import java
.util
.List
;
18 import org
.apache
.commons
.lang3
.StringUtils
;
19 import org
.joda
.time
.DateTime
;
20 import org
.joda
.time
.DateTimeFieldType
;
21 import org
.joda
.time
.Partial
;
22 import org
.joda
.time
.format
.DateTimeFormatter
;
23 import org
.joda
.time
.format
.DateTimeFormatterBuilder
;
24 import org
.springframework
.stereotype
.Component
;
26 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
27 import eu
.etaxonomy
.cdm
.common
.URI
;
28 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
29 import eu
.etaxonomy
.cdm
.filter
.TaxonNodeFilter
;
30 import eu
.etaxonomy
.cdm
.format
.reference
.NomenclaturalSourceFormatter
;
31 import eu
.etaxonomy
.cdm
.io
.common
.CdmExportBase
;
32 import eu
.etaxonomy
.cdm
.io
.common
.ExportResult
.ExportResultState
;
33 import eu
.etaxonomy
.cdm
.io
.common
.TaxonNodeOutStreamPartitioner
;
34 import eu
.etaxonomy
.cdm
.io
.common
.XmlExportState
;
35 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.IExportTransformer
;
36 import eu
.etaxonomy
.cdm
.model
.common
.AnnotatableEntity
;
37 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
38 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
39 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
40 import eu
.etaxonomy
.cdm
.model
.common
.ICdmBase
;
41 import eu
.etaxonomy
.cdm
.model
.common
.IIdentifiableEntity
;
42 import eu
.etaxonomy
.cdm
.model
.common
.Identifier
;
43 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
44 import eu
.etaxonomy
.cdm
.model
.common
.LanguageString
;
45 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
46 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
47 import eu
.etaxonomy
.cdm
.model
.name
.HomotypicalGroup
;
48 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
49 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
50 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
52 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
53 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
54 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
55 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
56 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNodeStatus
;
57 import eu
.etaxonomy
.cdm
.model
.term
.IdentifierType
;
60 * Classification or taxon tree exporter into WFO Backbone format.
62 * @see https://dev.e-taxonomy.eu/redmine/issues/10446
68 public class WfoBackboneExport
69 extends CdmExportBase
<WfoBackboneExportConfigurator
,WfoBackboneExportState
,IExportTransformer
,File
>{
71 private static final long serialVersionUID
= -4560488499411723333L;
73 public WfoBackboneExport() {
74 this.ioName
= this.getClass().getSimpleName();
78 public long countSteps(WfoBackboneExportState state
) {
79 TaxonNodeFilter filter
= state
.getConfig().getTaxonNodeFilter();
80 return getTaxonNodeService().count(filter
);
84 protected void doInvoke(WfoBackboneExportState state
) {
87 IProgressMonitor monitor
= state
.getConfig().getProgressMonitor();
88 WfoBackboneExportConfigurator config
= state
.getConfig();
91 if (config
.getTaxonNodeFilter().hasClassificationFilter()) {
92 Classification classification
= getClassificationService()
93 .load(config
.getTaxonNodeFilter().getClassificationFilter().get(0).getUuid());
94 state
.setRootId(classification
.getRootNode().getUuid());
95 } else if (config
.getTaxonNodeFilter().hasSubtreeFilter()) {
96 state
.setRootId(config
.getTaxonNodeFilter().getSubtreeFilter().get(0).getUuid());
99 @SuppressWarnings({ "unchecked", "rawtypes" })
100 TaxonNodeOutStreamPartitioner
<XmlExportState
> partitioner
= TaxonNodeOutStreamPartitioner
.NewInstance(this,
101 state
, state
.getConfig().getTaxonNodeFilter(), 100, monitor
, null);
103 // handleMetaData(state); //FIXME metadata;
104 monitor
.subTask("Start partitioning");
107 String baseUrl
= state
.getConfig().getSourceLinkBaseUrl();
108 if (baseUrl
!= null && !baseUrl
.startsWith("http://") && !baseUrl
.startsWith("https://")){
109 String message
= "Source link base url is not a http based url.";
110 state
.getResult().addWarning(message
);
114 TaxonNode node
= partitioner
.next();
115 while (node
!= null) {
116 handleTaxonNode(state
, node
);
117 node
= partitioner
.next();
120 state
.getProcessor().createFinalResult(state
);
121 } catch (Exception e
) {
122 state
.getResult().addException(e
,
123 "An unexpected error occurred in main method doInvoke() " + e
.getMessage());
128 private void handleTaxonNode(WfoBackboneExportState state
, TaxonNode taxonNode
) {
130 if (taxonNode
== null) {
131 // TODO 5 taxon node not found
132 String message
= "TaxonNode for given taxon node UUID not found.";
133 state
.getResult().addError(message
);
136 boolean exclude
= filterTaxon(state
, taxonNode
);
139 String parentWfoId
= getParentWfoId(state
, taxonNode
);
140 if (taxonNode
.hasTaxon()) {
142 state
.putTaxonNodeWfoId(taxonNode
, parentWfoId
); //always use parent instead
144 String wfoId
= handleTaxon(state
, taxonNode
, parentWfoId
);
145 state
.putTaxonNodeWfoId(taxonNode
, wfoId
);
148 } catch (Exception e
) {
149 state
.getResult().addException(e
, "An unexpected error occurred when handling taxonNode "
150 + taxonNode
.getUuid() + ": " + e
.getMessage() + e
.getStackTrace());
155 private String
getParentWfoId(WfoBackboneExportState state
, TaxonNode taxonNode
) {
156 TaxonNode parentNode
= taxonNode
.getParent();
157 if (parentNode
== null) {
160 String wfoId
= state
.getTaxonNodeWfoId(parentNode
);
164 wfoId
= parentNode
.getTaxon() == null ?
null
165 : getWfoId(state
, parentNode
.getTaxon().getName(), true);
167 state
.putTaxonNodeWfoId(parentNode
, wfoId
);
168 state
.putTaxonWfoId(parentNode
.getTaxon(), wfoId
);
169 state
.putNameWfoId(parentNode
.getTaxon().getName(), wfoId
);
176 private boolean filterTaxon(WfoBackboneExportState state
, TaxonNode taxonNode
) {
177 Taxon taxon
= taxonNode
.getTaxon();
181 TaxonName taxonName
= taxon
.getName();
182 if (taxonName
== null) {
184 }else if (taxonName
.isHybridFormula()) {
187 String wfoId
= getWfoId(state
, taxonName
, false);
193 Rank rank
= taxonName
.getRank();
195 //TODO 3 is missing rank handling correct?
198 if (rank
.isSpeciesAggregate()){
206 * @return the WFO-ID of the taxon
208 private String
handleTaxon(WfoBackboneExportState state
, TaxonNode taxonNode
, String parentWfoId
) {
211 if (taxonNode
== null) {
212 state
.getResult().addError("The taxonNode was null.", "handleTaxon");
213 state
.getResult().setState(ExportResultState
.INCOMPLETE_WITH_ERROR
);
217 if (taxonNode
.getTaxon() == null) {
218 state
.getResult().addError("There was a taxon node without a taxon: " + taxonNode
.getUuid(),
220 state
.getResult().setState(ExportResultState
.INCOMPLETE_WITH_ERROR
);
224 //deproxy, just in case
225 Taxon taxon
= CdmBase
.deproxy(taxonNode
.getTaxon());
231 //classification csvLine
232 WfoBackboneExportTable table
= WfoBackboneExportTable
.CLASSIFICATION
;
233 String
[] csvLine
= new String
[table
.getSize()];
236 TaxonName name
= taxon
.getName();
237 wfoId
= handleName(state
, table
, csvLine
, name
);
239 //... parentNameUsageID
240 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_PARENT_ID
)] = parentWfoId
;
243 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_SUBFAMILY
)] = null;
244 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_TRIBE
)] = null;
245 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_SUBTRIBE
)] = null;
246 //TODO 2 is subgenus handling correct?
247 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_SUBGENUS
)] = name
.isInfraGeneric()? name
.getInfraGenericEpithet() : null ;
249 //... tax status, TODO 2 are there other status for accepted or other reasons for being ambiguous
250 String taxonStatus
= taxon
.isDoubtful()?
"ambiguous" : "Accepted";
251 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_STATUS
)] = taxonStatus
;
253 //TODO 2 remarks, what exactly
254 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAXON_REMARKS
)] = getRemarks(name
);
256 //TODO 7 URL to taxon, take it from a repository information (currently not yet possible, but maybe we could use a CDM preference instead)
257 if (isNotBlank(state
.getConfig().getSourceLinkBaseUrl())) {
258 String taxonSourceLink
= makeTaxonSourceLink(state
, taxon
);
259 csvLine
[table
.getIndex(WfoBackboneExportTable
.REFERENCES
)] = taxonSourceLink
;
262 //TODO 1 excluded info
263 csvLine
[table
.getIndex(WfoBackboneExportTable
.EXCLUDE
)] = makeExcluded(state
, taxonNode
);
265 handleTaxonBase(state
, table
, csvLine
, taxon
);
267 handleSynonyms(state
, taxon
);
270 state
.getProcessor().put(table
, taxon
, csvLine
);
274 } catch (Exception e
) {
276 state
.getResult().addException(e
,
277 "An unexpected problem occurred when trying to export taxon with id " + taxon
.getId() + " " + taxon
.getTitleCache());
278 state
.getResult().setState(ExportResultState
.INCOMPLETE_WITH_ERROR
);
283 private String
makeExcluded(WfoBackboneExportState state
, TaxonNode taxonNode
) {
284 TaxonNodeStatus status
= taxonNode
.getStatus();
285 if (status
== null || (status
!= TaxonNodeStatus
.EXCLUDED
&& !status
.isKindOf(TaxonNodeStatus
.EXCLUDED
))) {
288 Language lang
= Language
.getDefaultLanguage(); //TODO 7 language for status note
290 String result
= status
== TaxonNodeStatus
.EXCLUDED ?
"Excluded" : status
.getLabel();
291 String note
= taxonNode
.preferredStatusNote(lang
);
292 result
= CdmUtils
.concat(": ", result
, note
);
297 private void handleTaxonBase(WfoBackboneExportState state
, WfoBackboneExportTable table
, String
[] csvLine
,
298 TaxonBase
<?
> taxonBase
) {
301 Reference secRef
= taxonBase
.getSec();
302 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_NAME_ACCORDING_TO_ID
)] = getId(state
, secRef
);
304 && (!state
.getReferenceStore().contains((secRef
.getUuid())))) {
305 handleReference(state
, secRef
);
309 csvLine
[table
.getIndex(WfoBackboneExportTable
.CREATED
)] = null;
312 csvLine
[table
.getIndex(WfoBackboneExportTable
.MODIFIED
)] = null;
316 private String
makeTaxonSourceLink(WfoBackboneExportState state
, Taxon taxon
) {
317 String baseUrl
= state
.getConfig().getSourceLinkBaseUrl();
318 if (!baseUrl
.endsWith("/")) {
321 String result
= baseUrl
+ "cdm_dataportal/taxon/" + taxon
.getUuid() ;
325 private String
makeSynonymSourceLink(WfoBackboneExportState state
, Synonym synonym
) {
326 String baseUrl
= state
.getConfig().getSourceLinkBaseUrl();
327 if (!baseUrl
.endsWith("/")) {
330 String result
= baseUrl
+ "cdm_dataportal/taxon/" +
331 synonym
.getAcceptedTaxon().getUuid()
332 + "/synonymy?highlite=" + synonym
.getUuid();
336 private void handleSynonyms(WfoBackboneExportState state
, Taxon taxon
) {
338 if (!state
.getConfig().isDoSynonyms()) {
342 //homotypic group / synonyms
343 HomotypicalGroup homotypicGroup
= taxon
.getHomotypicGroup();
344 handleHomotypicalGroup(state
, homotypicGroup
, taxon
);
345 for (Synonym syn
: taxon
.getSynonymsInGroup(homotypicGroup
)) {
346 handleSynonym(state
, syn
, true);
349 List
<HomotypicalGroup
> heterotypicHomotypicGroups
= taxon
.getHeterotypicSynonymyGroups();
350 for (HomotypicalGroup group
: heterotypicHomotypicGroups
){
351 handleHomotypicalGroup(state
, group
, taxon
);
352 for (Synonym syn
: taxon
.getSynonymsInGroup(group
)) {
353 handleSynonym(state
, syn
, false);
358 private boolean isUrl(String url
) {
360 if (url
.startsWith("http")) {
364 } catch (Exception e
) {
365 //exception should return false
370 private String
toIsoDate(TimePeriod mediaCreated
) {
371 //TODO 2 date, what if end or freetext exist?
372 Partial partial
= mediaCreated
.getStart();
373 if (partial
== null || !partial
.isSupported(DateTimeFieldType
.year())
374 || !partial
.isSupported(DateTimeFieldType
.monthOfYear()) && partial
.isSupported(DateTimeFieldType
.dayOfMonth())) {
375 //TODO 2 date, log warning, also if mediaCreated.getEnd() != null or so
378 DateTimeFormatter formatter
= new DateTimeFormatterBuilder()
379 .appendYear(4, 4).appendLiteral('-')
380 .appendMonthOfYear(2).appendLiteral('-')
383 return partial
.toString(formatter
);
388 * transforms the given date to an iso date
390 protected String
toIsoDate(DateTime dateTime
) {
391 if (dateTime
== null) {
394 DateTimeFormatter formatter
= new DateTimeFormatterBuilder()
395 .appendYear(4, 4).appendLiteral('-')
396 .appendMonthOfYear(2).appendLiteral('-')
399 return formatter
.print(dateTime
);
402 private String
getRemarks(AnnotatableEntity entity
) {
403 String remarks
= null;
404 for (Annotation a
: entity
.getAnnotations()) {
405 //TODO 3 handle other annotation types
406 if (AnnotationType
.EDITORIAL().equals(a
.getAnnotationType())
407 && CdmUtils
.isNotBlank(a
.getText())){
408 remarks
= CdmUtils
.concat(";", remarks
, a
.getText());
414 // private void handleMetaData(ColDpExportState state) {
415 // ColDpExportTable table = ColDpExportTable.METADATA;
416 // String[] csvLine = new String[table.getSize()];
417 //// csvLine[table.getIndex(CdmLightExportTable.INSTANCE_ID)] = state.getConfig().getInctanceId();
418 //// csvLine[table.getIndex(CdmLightExportTable.INSTANCE_NAME)] = state.getConfig().getInstanceName();
419 // csvLine[table.getIndex(ColDpExportTable.DATASET_BASE_URL)] = state.getConfig().getBase_url();
420 // csvLine[table.getIndex(ColDpExportTable.DATASET_CONTRIBUTOR)] = state.getConfig().getContributor();
421 // csvLine[table.getIndex(ColDpExportTable.DATASET_CREATOR)] = state.getConfig().getCreator();
422 // csvLine[table.getIndex(ColDpExportTable.DATASET_DESCRIPTION)] = state.getConfig().getDescription();
423 // csvLine[table.getIndex(ColDpExportTable.DATASET_DOWNLOAD_LINK)] = state.getConfig().getDataset_download_link();
424 // csvLine[table.getIndex(ColDpExportTable.DATASET_KEYWORDS)] = state.getConfig().getKeywords();
425 // csvLine[table.getIndex(ColDpExportTable.DATASET_LANDINGPAGE)] = state.getConfig().getDataSet_landing_page();
427 // csvLine[table.getIndex(ColDpExportTable.DATASET_LANGUAGE)] = state.getConfig().getLanguage() != null? state.getConfig().getLanguage().getLabel(): null;
428 // csvLine[table.getIndex(ColDpExportTable.DATASET_LICENCE)] = state.getConfig().getLicence();
429 // csvLine[table.getIndex(ColDpExportTable.DATASET_LOCATION)] = state.getConfig().getLocation();
430 // csvLine[table.getIndex(ColDpExportTable.DATASET_RECOMMENDED_CITATTION)] = state.getConfig().getRecommended_citation();
431 // csvLine[table.getIndex(ColDpExportTable.DATASET_TITLE)] = state.getConfig().getTitle();
432 // state.getProcessor().put(table, "", csvLine);
435 private String
createMultilanguageString(Map
<Language
, LanguageString
> multilanguageText
) {
437 int index
= multilanguageText
.size();
438 for (LanguageString langString
: multilanguageText
.values()) {
439 text
+= langString
.getText();
448 private String
createAnnotationsString(Set
<Annotation
> annotations
) {
449 StringBuffer strBuff
= new StringBuffer();
451 for (Annotation ann
: annotations
) {
452 if (ann
.getAnnotationType() == null || !ann
.getAnnotationType().equals(AnnotationType
.TECHNICAL())) {
453 strBuff
.append(ann
.getText());
454 strBuff
.append("; ");
458 if (strBuff
.length() > 2) {
459 return strBuff
.substring(0, strBuff
.length() - 2);
465 private void handleSource(WfoBackboneExportState state
, DescriptionElementBase element
,
466 WfoBackboneExportTable factsTable
) {
467 // ColDpExportTable table = ColDpExportTable.FACT_SOURCES;
469 // Set<DescriptionElementSource> sources = element.getSources();
471 // for (DescriptionElementSource source : sources) {
472 // if (!(source.getType().equals(OriginalSourceType.Import)
473 // && state.getConfig().isExcludeImportSources())) {
474 // String[] csvLine = new String[table.getSize()];
475 // Reference ref = source.getCitation();
476 // if ((ref == null) && (source.getNameUsedInSource() == null)) {
479 // if (ref != null) {
480 // if (!state.getReferenceStore().contains(ref.getUuid())) {
481 // handleReference(state, ref);
484 // csvLine[table.getIndex(ColDpExportTable.REFERENCE_FK)] = getId(state, ref);
486 // csvLine[table.getIndex(ColDpExportTable.FACT_FK)] = getId(state, element);
488 // csvLine[table.getIndex(ColDpExportTable.NAME_IN_SOURCE_FK)] = getId(state,
489 // source.getNameUsedInSource());
490 // csvLine[table.getIndex(ColDpExportTable.FACT_TYPE)] = factsTable.getTableName();
491 // if (StringUtils.isBlank(csvLine[table.getIndex(ColDpExportTable.REFERENCE_FK)])
492 // && StringUtils.isBlank(csvLine[table.getIndex(ColDpExportTable.NAME_IN_SOURCE_FK)])) {
495 // state.getProcessor().put(table, source, csvLine);
498 // } catch (Exception e) {
499 // state.getResult().addException(e, "An unexpected error occurred when handling single source "
500 // + cdmBaseStr(element) + ": " + e.getMessage());
504 private String
getTitleCache(IIdentifiableEntity identEntity
) {
505 if (identEntity
== null) {
508 // TODO 3 titleCache refresh?
509 return identEntity
.getTitleCache();
512 private String
getId(WfoBackboneExportState state
, ICdmBase cdmBase
) {
513 if (cdmBase
== null) {
516 // TODO 4 id type, make configurable
517 return cdmBase
.getUuid().toString();
520 private void handleSynonym(WfoBackboneExportState state
, Synonym synonym
, boolean isHomotypic
) {
522 if (isUnpublished(state
.getConfig(), synonym
)) {
526 WfoBackboneExportTable table
= WfoBackboneExportTable
.CLASSIFICATION
;
527 String
[] csvLine
= new String
[table
.getSize()];
529 TaxonName name
= synonym
.getName();
530 handleName(state
, table
, csvLine
, name
);
533 if (synonym
.getAcceptedTaxon()!= null && synonym
.getAcceptedTaxon().getName() != null) {
534 TaxonName acceptedName
= synonym
.getAcceptedTaxon().getName();
535 String acceptedWfoId
= getWfoId(state
, acceptedName
, false);
536 if (acceptedWfoId
== null) {
537 String message
= "WFO-ID for accepted name is missing. This should not happen. Synonym: " + name
.getTitleCache() + "; Accepted name: " + acceptedName
.getTitleCache();
538 state
.getResult().addError(message
, "handleName");
539 state
.getResult().setState(ExportResultState
.INCOMPLETE_WITH_ERROR
);
541 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_ACCEPTED_NAME_ID
)] = acceptedWfoId
;
545 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_STATUS
)] = isHomotypic ?
"homotypicSynonym" : "heterotypicSynonym";
547 //TODO 7 URL to taxon, take it from a repository information (currently not yet possible, but maybe we could use a CDM preference instead)
548 if (isNotBlank(state
.getConfig().getSourceLinkBaseUrl())) {
549 String taxonSourceLink
= makeSynonymSourceLink(state
, synonym
);
550 csvLine
[table
.getIndex(WfoBackboneExportTable
.REFERENCES
)] = taxonSourceLink
;
553 handleTaxonBase(state
, table
, csvLine
, synonym
);
555 state
.getProcessor().put(table
, synonym
, csvLine
);
556 } catch (Exception e
) {
557 state
.getResult().addException(e
, "An unexpected error occurred when handling synonym "
558 + cdmBaseStr(synonym
) + ": " + e
.getMessage());
562 private String
handleName(WfoBackboneExportState state
, WfoBackboneExportTable table
, String
[] csvLine
,
565 name
= CdmBase
.deproxy(name
);
566 if (name
== null || state
.getNameStore().containsKey(name
.getId())) {
568 state
.getResult().addError("No name was given for taxon.", "handleName");
569 state
.getResult().setState(ExportResultState
.INCOMPLETE_WITH_ERROR
);
576 Rank rank
= name
.getRank();
577 state
.getNameStore().put(name
.getId(), name
.getUuid());
580 wfoId
= getWfoId(state
, name
, true);
581 if (isBlank(wfoId
)) {
582 String message
= "No WFO-ID given for taxon " + name
.getTitleCache() + ". Taxon ignored";
583 state
.getResult().addError(message
);
584 state
.getResult().setState(ExportResultState
.INCOMPLETE_WITH_ERROR
);
587 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAXON_ID
)] = wfoId
;
590 //TODO 9 add IPNI ID if exists, scientific name ID
591 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_SCIENTIFIC_NAME_ID
)] = null;
594 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_LOCAL_ID
)] = getId(state
, name
);
597 if (name
.isProtectedTitleCache()) {
598 //TODO 7 make it configurable if we should always take titleCache if titleCache is protected, as nameCache may not necessarily
599 // have complete data if titleCache is protected as it is considered to be irrelevant or at least preliminary
601 if (StringUtils
.isNotEmpty(name
.getNameCache())) {
602 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_SCIENTIFIC_NAME
)] = name
.getNameCache();
603 message
= "ScientificName: Name cache " + name
.getNameCache() + " used for name with protected titleCache " + name
.getTitleCache();
605 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_SCIENTIFIC_NAME
)] = name
.getTitleCache();
606 message
= "ScientificName: Name has protected titleCache and no explicit nameCache: " + name
.getTitleCache();
608 state
.getResult().addWarning(message
); //TODO 7 add location to warning
610 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_SCIENTIFIC_NAME
)] = name
.getNameCache();
614 String rankStr
= state
.getTransformer().getCacheByRank(rank
);
615 if (rankStr
== null) {
616 String message
= rank
== null ?
"No rank" : ("Rank not supported by WFO:" + rank
.getLabel())
617 + "Taxon not handled in export: " + name
.getTitleCache();
618 state
.getResult().addWarning(message
); //TODO 2 warning sufficient for missing rank? + location
621 csvLine
[table
.getIndex(WfoBackboneExportTable
.RANK
)] = rankStr
;
624 //TODO 3 handle empty authorship cache warning
625 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_AUTHORSHIP
)] = name
.getAuthorshipCache();
627 //family (use familystr if provided, otherwise try to compute from the family taxon
628 String familyStr
= state
.getFamilyStr();
629 if (StringUtils
.isBlank(familyStr
)){
630 if (Rank
.FAMILY().equals(name
.getRank())){
631 familyStr
= name
.getNameCache();
633 if (StringUtils
.isNotBlank(familyStr
)) {
634 state
.setFamilyStr(familyStr
);
636 String message
= "Obligatory family information is missing";
637 state
.getResult().addWarning(message
);
640 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_FAMILY
)] = state
.getFamilyStr();
643 csvLine
[table
.getIndex(WfoBackboneExportTable
.TAX_GENUS
)] = name
.isSupraGeneric()?
null : name
.getGenusOrUninomial();
644 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_SPECIFIC_EPITHET
)] = name
.getSpecificEpithet();
645 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_INFRASPECIFIC_EPITHET
)] = name
.getInfraSpecificEpithet();
647 //TODO 3 verbatimTaxonRank, is this needed at all?
648 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_VERBATIM_RANK
)] = rankStr
;
651 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_STATUS
)] = makeNameStatus(state
, name
);
654 String nomRef
= NomenclaturalSourceFormatter
.INSTANCE().format(name
.getNomenclaturalSource());
655 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_PUBLISHED_IN
)] = nomRef
;
658 TaxonName originalName
= name
.getBasionym(); //TODO 5 basionym, order in case there are >1 basionyms
659 if (originalName
== null) {
660 originalName
= name
.getReplacedSynonyms().stream().findFirst().orElse(null);
663 if (originalName
!= null) {
664 if (!state
.getNameStore().containsKey(originalName
.getId())) {
665 //TODO 1 handle basionym is in file assertion
667 String basionymId
= getWfoId(state
, originalName
, false);
668 csvLine
[table
.getIndex(WfoBackboneExportTable
.NAME_ORIGINAL_NAME_ID
)] = basionymId
;
671 //TODO 1 related names like orth. var., original spelling,
673 } catch (Exception e
) {
674 state
.getResult().addException(e
,
675 "An unexpected error occurred when handling the name " + cdmBaseStr(name
) + ": " + name
.getTitleCache() + ": " + e
.getMessage());
683 private String
getWfoId(WfoBackboneExportState state
, TaxonName name
, boolean warnIfNotExists
) {
684 Identifier wfoId
= name
.getIdentifier(IdentifierType
.uuidWfoNameIdentifier
);
685 if (wfoId
== null && warnIfNotExists
) {
686 String message
= "No wfo-id given for name: " + name
.getTitleCache()+"/"+ name
.getUuid();
687 state
.getResult().addWarning(message
); //TODO 5 data location
689 return wfoId
== null ?
null : wfoId
.getIdentifier();
692 private String
makeNameStatus(WfoBackboneExportState state
, TaxonName name
) {
695 //TODO 1 what is with dubium
696 if (name
.isLegitimate()) {
697 if (name
.isConserved()) {
702 } else if (name
.isRejected()) {
704 } else if (name
.isIllegitimate()) {
705 return "Illegitimate";
706 } else if (name
.isInvalid()) {
707 //TODO 1 handle original spellings for name status
708 if (name
.isOrthographicVariant()) {
709 return "orthografia";
714 String message
= "Unhandled name status case for name: " + name
.getTitleCache() +
715 ". Status not handled correctly.";
716 state
.getResult().addWarning(message
);
719 } catch (Exception e
) {
720 state
.getResult().addException(e
, "An unexpected error occurred when extracting status string for "
721 + cdmBaseStr(name
) + ": " + e
.getMessage());
726 private void handleHomotypicalGroup(WfoBackboneExportState state
, HomotypicalGroup group
, Taxon acceptedTaxon
) {
729 List
<TaxonName
> typifiedNames
= new ArrayList
<>();
730 if (acceptedTaxon
!= null){
731 List
<Synonym
> synonymsInGroup
= acceptedTaxon
.getSynonymsInGroup(group
);
732 if (group
.equals(acceptedTaxon
.getHomotypicGroup())){
733 typifiedNames
.add(acceptedTaxon
.getName());
735 synonymsInGroup
.stream().forEach(synonym
-> typifiedNames
.add(CdmBase
.deproxy(synonym
.getName())));
739 TaxonName firstname
= null;
740 for (TaxonName name
: typifiedNames
){
741 Iterator
<Taxon
> taxa
= name
.getTaxa().iterator();
742 while(taxa
.hasNext()){
743 Taxon taxon
= taxa
.next();
744 if(!(taxon
.isMisapplication() || taxon
.isProparteSynonym())){
751 } catch (Exception e
) {
752 state
.getResult().addException(e
, "An unexpected error occurred when handling homotypic group "
753 + cdmBaseStr(group
) + ": " + e
.getMessage());
757 private void handleReference(WfoBackboneExportState state
, Reference reference
) {
759 if (state
.getReferenceStore().contains(reference
.getUuid())) {
762 reference
= CdmBase
.deproxy(reference
);
764 state
.addReferenceToStore(reference
);
765 WfoBackboneExportTable table
= WfoBackboneExportTable
.REFERENCE
;
766 String
[] csvLine
= new String
[table
.getSize()];
768 csvLine
[table
.getIndex(WfoBackboneExportTable
.IDENTIFIER
)] = getId(state
, reference
);
770 //TODO 2 correct?, ref biblio citation
771 csvLine
[table
.getIndex(WfoBackboneExportTable
.REF_BIBLIO_CITATION
)] = reference
.getCitation();
774 if (reference
.getDoi() != null) {
775 csvLine
[table
.getIndex(WfoBackboneExportTable
.REF_URI
)] = reference
.getDoiString();
777 //TODO 2 handle other reference links, e.g. external links
779 //// csvLine[table.getIndex(ColDpExportTable.LINK)] = null;
780 // if (reference.getUri() != null) {
781 // csvLine[table.getIndex(WfoBackboneExportTable.LINK)] = reference.getUri().toString();
784 state
.getProcessor().put(table
, reference
, csvLine
);
785 } catch (Exception e
) {
787 state
.getResult().addException(e
, "An unexpected error occurred when handling reference "
788 + cdmBaseStr(reference
) + ": " + e
.getMessage());
793 * Returns a string representation of the {@link CdmBase cdmBase} object for
796 private String
cdmBaseStr(CdmBase cdmBase
) {
797 if (cdmBase
== null) {
798 return "-no object available-";
800 return cdmBase
.getClass().getSimpleName() + ": " + cdmBase
.getUuid();
805 protected boolean doCheck(WfoBackboneExportState state
) {
810 protected boolean isIgnore(WfoBackboneExportState state
) {