3 * Copyright (C) 2017 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.io
.bogota
;
13 import java
.util
.UUID
;
15 import org
.apache
.log4j
.Logger
;
16 import org
.springframework
.stereotype
.Component
;
17 import org
.springframework
.transaction
.TransactionStatus
;
19 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
20 import eu
.etaxonomy
.cdm
.io
.mexico
.SimpleExcelTaxonImport
;
21 import eu
.etaxonomy
.cdm
.io
.mexico
.SimpleExcelTaxonImportState
;
22 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
23 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
24 import eu
.etaxonomy
.cdm
.model
.name
.IBotanicalName
;
25 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
26 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
27 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
28 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
29 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
30 import eu
.etaxonomy
.cdm
.model
.taxon
.ITaxonTreeNode
;
31 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
32 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymType
;
33 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
34 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
35 import eu
.etaxonomy
.cdm
.strategy
.homotypicgroup
.BasionymRelationCreator
;
36 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
43 public class BogotaChecklistTaxonImport
<CONFIG
extends BogotaChecklistImportConfigurator
>
44 extends SimpleExcelTaxonImport
<CONFIG
> {
46 private static final long serialVersionUID
= -884838817884874228L;
47 private static final Logger logger
= Logger
.getLogger(BogotaChecklistTaxonImport
.class);
49 private static final String ID_COL
= "#";
50 private static final String AUTHOR
= "Autor";
51 private static final String NAME
= "Nombre";
52 private static final String GENUS
= "GĂ©nero";
53 private static final String FAMILIA
= "Familia";
54 private static final String INFRASPECIFIC
= "Taxones infraespecĂficos";
55 private static final String SINONIMOS
= "Sinonimos";
57 private static UUID rootUuid
= UUID
.fromString("d66eda18-4c11-4472-bfe8-f6cd5ed95c9f");
58 private static UUID plantaeUuid
= UUID
.fromString("032fc183-eb4f-4f19-a290-28597a849096");
60 private String lastGenus
;
61 private NonViralNameParserImpl parser
= NonViralNameParserImpl
.NewInstance();
62 private BasionymRelationCreator basionymCreator
= new BasionymRelationCreator();
66 protected String
getWorksheetName(CONFIG config
) {
67 return "Resultados Busqueda Avanzada";
70 private boolean isFirst
= true;
71 private TransactionStatus tx
= null;
74 protected void firstPass(SimpleExcelTaxonImportState
<CONFIG
> state
) {
76 tx
= this.startTransaction();
80 String line
= state
.getCurrentLine() + ": ";
81 Map
<String
, String
> record
= state
.getOriginalRecord();
83 String noStr
= getValue(record
, ID_COL
);
86 TaxonNode taxonNode
= makeTaxon(state
, line
, record
, noStr
);
88 if (taxonNode
!= null){
90 makeSynonyms(state
, record
, line
, taxonNode
.getTaxon(), noStr
);
93 makeInfraSpecific(state
, record
, line
, taxonNode
, noStr
);
95 logger
.warn(line
+ "No taxon node given");
101 protected void secondPass(SimpleExcelTaxonImportState
<CONFIG
> state
) {
103 this.commitTransaction(tx
);
114 private void makeSynonyms(SimpleExcelTaxonImportState
<CONFIG
> state
, Map
<String
, String
> record
, String line
,
115 Taxon taxon
, String noStr
) {
117 String synonymsStr
= getValue(record
, SINONIMOS
);
118 if (synonymsStr
!= null){
119 String
[] splits
= synonymsStr
.split(",");
120 for(String split
: splits
){
121 split
= split
.trim();
122 boolean isMisapplied
= split
.contains("auct.") || split
.contains(" sensu ");
123 if (split
.endsWith(" None")){
124 split
= split
.replace(" None", "").trim();
127 handleSingleMisapplied(state
, split
, line
, taxon
, noStr
);
129 handleSingleSynonym(state
, split
, line
, taxon
, noStr
);
133 basionymCreator
.invoke(taxon
);
143 private void handleSingleMisapplied(SimpleExcelTaxonImportState
<CONFIG
> state
, String nameStr
, String line
,
144 Taxon taxon
, String noStr
) {
145 Rank rank
= Rank
.SPECIES();
146 String AUCT_NON
= "auct. non ";
147 String auctStr
= nameStr
.contains(AUCT_NON
)? AUCT_NON
: nameStr
.endsWith("auct.")?
"auct.": null;
148 boolean auctRequired
= false;
149 if (auctStr
== null){
151 if (nameStr
.endsWith("auct.colomb.")){
152 nameStr
= nameStr
.replace(" auct.colomb.", "");
153 auctStr
= "auct.colomb.";
154 }else if (nameStr
.endsWith(" [auct.mult.non Sw.]")){
155 nameStr
= nameStr
.replace(" [auct.mult.non Sw.]", "");
156 auctStr
= "[auct.mult.non Sw.]";
157 }else if (nameStr
.endsWith(" auct.pr.p.")){
158 nameStr
= nameStr
.replace(" auct.pr.p.", "");
159 auctStr
= "auct.pr.p.";
160 }else if (nameStr
.contains(" sensu ")){
161 logger
.warn(line
+ "sensu not yet handled correctly:" + nameStr
);
162 auctRequired
= false;
164 auctRequired
= false;
165 logger
.warn(line
+ "auct. not recognized: " + nameStr
);
169 nameStr
= nameStr
.replace(auctStr
, "").trim();
171 TaxonName name
= (TaxonName
)parser
.parseFullName(nameStr
, state
.getConfig().getNomenclaturalCode(), rank
);
172 name
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
173 name
= state
.getDeduplicationHelper().getExistingName(name
);
174 if (name
.isProtectedTitleCache()){
175 logger
.warn(line
+ "Misapplied name could not be parsed: " + nameStr
);
177 state
.getDeduplicationHelper().replaceAuthorNamesAndNomRef(name
);
179 Taxon misApp
= Taxon
.NewInstance(name
, null);
181 misApp
.setAppendedPhrase(auctStr
);
183 misApp
.addImportSource(noStr
, getNamespace(state
.getConfig()),
184 getSourceCitation(state
), null);
185 taxon
.addMisappliedName(misApp
, state
.getConfig().getSecReference(), null);
188 private String
getNamespace(CONFIG config
) {
189 return getWorksheetName(config
)+"."+ ID_COL
;
192 private void handleSingleSynonym(SimpleExcelTaxonImportState
<CONFIG
> state
, String nameStr
,
193 String line
, Taxon taxon
, String noStr
) {
194 Rank rank
= Rank
.SPECIES();
195 TaxonName name
= (TaxonName
)parser
.parseFullName(nameStr
, state
.getConfig().getNomenclaturalCode(), rank
);
196 name
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
197 name
= state
.getDeduplicationHelper().getExistingName(name
);
198 if (name
.isProtectedTitleCache()){
199 logger
.warn(line
+ "Synonym could not be parsed: " + nameStr
);
201 state
.getDeduplicationHelper().replaceAuthorNamesAndNomRef(name
);
203 Synonym synonym
= Synonym
.NewInstance(name
, getSecReference(state
));
204 synonym
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
205 taxon
.addSynonym(synonym
, SynonymType
.SYNONYM_OF());
208 private void makeInfraSpecific(SimpleExcelTaxonImportState
<CONFIG
> state
, Map
<String
, String
> record
, String line
,
209 TaxonNode speciesNode
, String noStr
) {
210 String subSpeciesStr
= getValue(record
, INFRASPECIFIC
);
211 if (subSpeciesStr
!= null){
212 String
[] splits
= subSpeciesStr
.split(",");
213 for(String split
: splits
){
214 if (split
.endsWith(" None")){
215 split
= split
.replace(" None", "").trim();
217 Rank rank
= Rank
.SUBSPECIES();
218 TaxonName name
= (TaxonName
)parser
.parseFullName(split
.trim(), state
.getConfig().getNomenclaturalCode(), rank
);
219 name
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
220 name
= state
.getDeduplicationHelper().getExistingName(name
);
221 if (name
.isProtectedTitleCache()){
222 logger
.warn(line
+ "Infraspecific taxon could not be parsed: " + split
.trim());
224 state
.getDeduplicationHelper().replaceAuthorNamesAndNomRef(name
);
226 Taxon subSpecies
= Taxon
.NewInstance(name
, getSecReference(state
));
227 subSpecies
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
228 TaxonNode subSpeciesNode
= speciesNode
.addChildTaxon(subSpecies
, getSecReference(state
), null);
229 getTaxonNodeService().save(subSpeciesNode
);
234 private TaxonNode
makeTaxon(SimpleExcelTaxonImportState
<CONFIG
> state
, String line
, Map
<String
, String
> record
,
237 TaxonNode familyTaxon
= getFamilyTaxon(record
, state
);
238 if (familyTaxon
== null){
239 logger
.warn(line
+ "Family not created: " + record
.get(FAMILIA
));
242 String genusStr
= getValue(record
, GENUS
);
243 String nameStr
= getValue(record
, NAME
);
244 String speciesAuthorStr
= getValue(record
, AUTHOR
);
246 nameStr
= CdmUtils
.concat(" ", nameStr
, speciesAuthorStr
);
247 Rank rank
= Rank
.SPECIES();
248 TaxonName name
= (TaxonName
)parser
.parseFullName(nameStr
, state
.getConfig().getNomenclaturalCode(), rank
);
249 name
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
250 name
= state
.getDeduplicationHelper().getExistingName(name
);
251 if (name
.isProtectedTitleCache()){
252 logger
.warn(line
+ "Name could not be parsed: " + nameStr
);
254 state
.getDeduplicationHelper().replaceAuthorNamesAndNomRef(name
);
256 Taxon taxon
= Taxon
.NewInstance(name
, getSecReference(state
));
258 taxon
.addImportSource(noStr
, getNamespace(state
.getConfig()), getSourceCitation(state
), null);
260 String parentStr
= genusStr
;
261 boolean genusAsBefore
= genusStr
.equals(lastGenus
);
262 TaxonNode parent
= getParent(state
, parentStr
);
266 //everything as expected
267 newNode
= parent
.addChildTaxon(taxon
, getSecReference(state
), null);
268 getTaxonNodeService().save(newNode
);
270 logger
.warn(line
+ "Unexpected non-missing parent");
275 logger
.warn(line
+ "Unexpected missing genus parent");
278 parent
= makeGenusNode(state
, record
, genusStr
);
279 newNode
= parent
.addChildTaxon(taxon
, getSecReference(state
), null);
280 getTaxonNodeService().save(newNode
);
284 this.lastGenus
= genusStr
;
293 private TaxonNode
getFamilyTaxon(Map
<String
, String
> record
, SimpleExcelTaxonImportState
<CONFIG
> state
) {
294 String familyStr
= getValue(record
, FAMILIA
);
295 if (familyStr
== null){
298 familyStr
= familyStr
.trim();
300 Taxon family
= state
.getHigherTaxon(familyStr
);
301 TaxonNode familyNode
;
303 familyNode
= family
.getTaxonNodes().iterator().next();
305 IBotanicalName name
= makeFamilyName(state
, familyStr
);
306 Reference sec
= getSecReference(state
);
307 family
= Taxon
.NewInstance(name
, sec
);
309 ITaxonTreeNode classificationNode
= getClassification(state
);
310 familyNode
= classificationNode
.addChildTaxon(family
, sec
, null);
311 state
.putHigherTaxon(familyStr
, family
);
312 getTaxonNodeService().save(familyNode
);
319 private TaxonNode rootNode
;
320 private TaxonNode
getClassification(SimpleExcelTaxonImportState
<CONFIG
> state
) {
321 if (rootNode
== null){
322 Reference sec
= getSecReference(state
);
323 String classificationName
= state
.getConfig().getClassificationName();
324 Language language
= Language
.DEFAULT();
325 Classification classification
= Classification
.NewInstance(classificationName
, sec
, language
);
326 classification
.setUuid(state
.getConfig().getClassificationUuid());
327 classification
.getRootNode().setUuid(rootUuid
);
329 IBotanicalName plantaeName
= TaxonNameFactory
.NewBotanicalInstance(Rank
.KINGDOM());
330 plantaeName
.setGenusOrUninomial("Plantae");
331 Taxon plantae
= Taxon
.NewInstance(plantaeName
, sec
);
332 TaxonNode plantaeNode
= classification
.addChildTaxon(plantae
, null, null);
333 plantaeNode
.setUuid(plantaeUuid
);
334 getClassificationService().save(classification
);
336 rootNode
= plantaeNode
;
342 protected IBotanicalName
makeFamilyName(SimpleExcelTaxonImportState
<CONFIG
> state
, String famStr
) {
343 IBotanicalName name
= TaxonNameFactory
.NewBotanicalInstance(Rank
.FAMILY());
344 famStr
= decapitalize(famStr
);
345 name
.setGenusOrUninomial(famStr
);
346 name
.addSource(makeOriginalSource(state
));
355 protected IdentifiableSource
makeOriginalSource(SimpleExcelTaxonImportState
<CONFIG
> state
) {
356 return IdentifiableSource
.NewDataImportInstance(getValue(state
.getOriginalRecord(),ID_COL
),
357 getNamespace(state
.getConfig()), state
.getConfig().getSourceReference());
364 private String
decapitalize(String famStr
) {
365 String result
= famStr
.substring(0,1) + famStr
.substring(1).toLowerCase();
370 protected Reference
getSecReference(SimpleExcelTaxonImportState
<CONFIG
> state
) {
371 return state
.getConfig().getSecReference();
378 protected Reference
getSourceCitation(SimpleExcelTaxonImportState
<CONFIG
> state
) {
379 return state
.getConfig().getSourceReference();
387 private TaxonNode
getParent(SimpleExcelTaxonImportState
<CONFIG
> state
, String parentStr
) {
388 Taxon taxon
= state
.getHigherTaxon(parentStr
);
390 return taxon
== null ?
null : taxon
.getTaxonNodes().iterator().next();
399 private TaxonNode
makeGenusNode(SimpleExcelTaxonImportState
<CONFIG
> state
,
400 Map
<String
, String
> record
, String genusStr
) {
401 IBotanicalName name
= TaxonNameFactory
.NewBotanicalInstance(Rank
.GENUS());
402 name
.setGenusOrUninomial(genusStr
);
403 Taxon genus
= Taxon
.NewInstance(name
, getSecReference(state
));
404 TaxonNode family
= getFamilyTaxon(record
, state
);
405 TaxonNode genusNode
= family
.addChildTaxon(genus
, getSecReference(state
), null);
406 state
.putHigherTaxon(genusStr
, genus
);
407 genus
.addSource(makeOriginalSource(state
));
408 getTaxonNodeService().save(genusNode
);