2 * Copyright (C) 2007 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.
10 package eu
.etaxonomy
.cdm
.io
.excel
.taxa
;
12 import java
.net
.MalformedURLException
;
14 import java
.net
.URISyntaxException
;
15 import java
.util
.Arrays
;
16 import java
.util
.HashMap
;
17 import java
.util
.HashSet
;
18 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import org
.apache
.commons
.lang
.StringUtils
;
24 import org
.apache
.log4j
.Logger
;
25 import org
.springframework
.stereotype
.Component
;
27 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
28 import eu
.etaxonomy
.cdm
.io
.excel
.common
.ExcelRowBase
.SourceDataHolder
;
29 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
30 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
31 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
32 import eu
.etaxonomy
.cdm
.model
.common
.DescriptionElementSource
;
33 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
34 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
35 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
36 import eu
.etaxonomy
.cdm
.model
.common
.OriginalSourceType
;
37 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
38 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
39 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
40 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
41 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
42 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
43 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
44 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
45 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
46 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
47 import eu
.etaxonomy
.cdm
.model
.location
.TdwgArea
;
48 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
49 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
50 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
51 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
52 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
53 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
54 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceFactory
;
55 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
56 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
57 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
58 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
59 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
60 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.StringNotParsableException
;
61 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
62 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
65 * @author a.babadshanjan
70 public class NormalExplicitImport
extends TaxonExcelImporterBase
{
71 private static final Logger logger
= Logger
.getLogger(NormalExplicitImport
.class);
73 public static Set
<String
> validMarkers
= new HashSet
<String
>(Arrays
.asList(new String
[]{"", "valid", "accepted", "a", "v", "t"}));
74 public static Set
<String
> synonymMarkers
= new HashSet
<String
>(Arrays
.asList(new String
[]{"", "invalid", "synonym", "s", "i"}));
75 public static final UUID uuidRefExtension
= UUID
.fromString("a46533df-7a78-448f-9b80-36d087fbdf2a");
78 * @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#analyzeSingleValue(eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase.KeyValue, eu.etaxonomy.cdm.io.excel.common.ExcelImportState)
81 protected void analyzeSingleValue(KeyValue keyValue
, TaxonExcelImportState state
) {
83 NormalExplicitRow normalExplicitRow
= state
.getCurrentRow();
84 String key
= keyValue
.key
;
85 String value
= keyValue
.value
;
86 Integer index
= keyValue
.index
;
87 if (key
.equalsIgnoreCase(ID_COLUMN
)) {
88 int ivalue
= floatString2IntValue(value
);
89 normalExplicitRow
.setId(ivalue
);
91 } else if(key
.equalsIgnoreCase(PARENT_ID_COLUMN
)) {
92 int ivalue
= floatString2IntValue(value
);
93 normalExplicitRow
.setParentId(ivalue
);
95 } else if(key
.equalsIgnoreCase(RANK_COLUMN
)) {
96 normalExplicitRow
.setRank(value
);
98 } else if(key
.equalsIgnoreCase(SCIENTIFIC_NAME_COLUMN
)) {
99 normalExplicitRow
.setScientificName(value
);
101 } else if(key
.equalsIgnoreCase(AUTHOR_COLUMN
)) {
102 normalExplicitRow
.setAuthor(value
);
104 } else if(key
.equalsIgnoreCase(NAME_STATUS_COLUMN
)) {
105 normalExplicitRow
.setNameStatus(value
);
107 } else if(key
.equalsIgnoreCase(VERNACULAR_NAME_COLUMN
)) {
108 normalExplicitRow
.setCommonName(value
);
110 } else if(key
.equalsIgnoreCase(LANGUAGE_COLUMN
)) {
111 normalExplicitRow
.setLanguage(value
);
113 } else if(key
.equalsIgnoreCase(TDWG_COLUMN
)) {
114 //TODO replace still necessary?
115 value
= value
.replace(".0", "");
116 normalExplicitRow
.putDistribution(index
, value
);
118 } else if(key
.equalsIgnoreCase(PROTOLOGUE_COLUMN
)) {
119 normalExplicitRow
.putProtologue(index
, value
);
121 } else if(key
.equalsIgnoreCase(IMAGE_COLUMN
)) {
122 normalExplicitRow
.putImage(index
, value
);
125 if (analyzeFeatures(state
, keyValue
)){
128 String message
= "Unexpected column header " + key
;
129 fireWarningEvent(message
, state
, 10);
130 state
.setUnsuccessfull();
131 logger
.error(message
);
139 * Create base taxa and add all information attached to it's name.
142 protected void firstPass(TaxonExcelImportState state
) {
147 // System.out.println("FP:" + state.getCurrentLine());
149 NormalExplicitRow taxonDataHolder
= state
.getCurrentRow();
151 String rankStr
= taxonDataHolder
.getRank();
152 String taxonNameStr
= taxonDataHolder
.getScientificName();
153 String authorStr
= taxonDataHolder
.getAuthor();
154 String nameStatus
= taxonDataHolder
.getNameStatus();
155 Integer id
= taxonDataHolder
.getId();
156 UUID cdmUuid
= taxonDataHolder
.getCdmUuid();
158 TaxonBase
<?
> taxonBase
= null;
159 if (cdmUuid
!= null){
160 taxonBase
= getTaxonService().find(cdmUuid
);
162 if (CdmUtils
.isNotEmpty(taxonNameStr
)) {
166 rank
= Rank
.getRankByNameOrAbbreviation(rankStr
);
167 } catch (UnknownCdmTypeException ex
) {
169 rank
= Rank
.getRankByEnglishName(rankStr
, state
.getConfig().getNomenclaturalCode(), false);
170 } catch (UnknownCdmTypeException e
) {
171 state
.setUnsuccessfull();
172 logger
.error(rankStr
+ " is not a valid rank.");
177 taxonBase
= createTaxon(state
, rank
, taxonNameStr
, authorStr
, nameStatus
);
182 if (taxonBase
== null){
183 String message
= "Taxon could not be created. Record will not be handled";
184 fireWarningEvent(message
, "Record: " + state
.getCurrentLine(), 6);
185 logger
.warn(message
);
186 state
.setUnsuccessfull();
191 for (String protologue
: taxonDataHolder
.getProtologues()){
192 TextData textData
= TextData
.NewInstance(Feature
.PROTOLOGUE());
193 this.getNameDescription(taxonBase
.getName()).addElement(textData
);
196 uri
= new URI(protologue
);
197 textData
.addMedia(Media
.NewInstance(uri
, null, null, null));
198 } catch (URISyntaxException e
) {
199 String warning
= "URISyntaxException when trying to convert to URI: " + protologue
;
200 logger
.error(warning
);
201 state
.setUnsuccessfull();
205 state
.putTaxon(id
, taxonBase
);
206 getTaxonService().save(taxonBase
);
214 * Stores parent-child, synonym and common name relationships.
215 * Adds all taxon related descriptive information (this is not done in the first pass
216 * because the information may also be attached to a synonym).
219 protected void secondPass(TaxonExcelImportState state
) {
220 System
.out
.println(state
.getCurrentLine());
222 NormalExplicitRow taxonDataHolder
= state
.getCurrentRow();
223 String taxonNameStr
= taxonDataHolder
.getScientificName();
224 String nameStatus
= taxonDataHolder
.getNameStatus();
225 String commonNameStr
= taxonDataHolder
.getCommonName();
226 Integer parentId
= taxonDataHolder
.getParentId();
227 Integer childId
= taxonDataHolder
.getId();
228 UUID cdmUuid
= taxonDataHolder
.getCdmUuid();
230 TaxonNameBase
<?
,?
> nameUsedInSource
;
232 if (cdmUuid
!= null){
233 TaxonBase
<?
> taxonBase
= getTaxonService().find(cdmUuid
);
234 acceptedTaxon
= getAcceptedTaxon(taxonBase
);
235 nameUsedInSource
= taxonBase
.getName();
237 //TODO error handling for class cast
238 Taxon parentTaxon
= CdmBase
.deproxy(state
.getTaxonBase(parentId
), Taxon
.class);
239 if (CdmUtils
.isNotEmpty(taxonNameStr
)) {
240 TaxonBase
<?
> taxonBase
= state
.getTaxonBase(childId
);
241 nameUsedInSource
= taxonBase
.getName();
242 nameStatus
= CdmUtils
.Nz(nameStatus
).trim().toLowerCase();
243 if (validMarkers
.contains(nameStatus
)){
244 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
245 acceptedTaxon
= taxon
;
246 // Add the parent relationship
247 if (state
.getCurrentRow().getParentId() != 0) {
248 if (parentTaxon
!= null) {
249 //Taxon taxon = (Taxon)state.getTaxonBase(childId);
251 Reference
<?
> citation
= state
.getConfig().getSourceReference();
252 String microCitation
= null;
253 Taxon childTaxon
= taxon
;
254 makeParent(state
, parentTaxon
, childTaxon
, citation
, microCitation
);
255 getTaxonService().saveOrUpdate(parentTaxon
);
257 String message
= "Taxonomic parent not found for " + taxonNameStr
;
258 logger
.warn(message
);
259 fireWarningEvent(message
, state
, 6);
260 state
.setUnsuccessfull();
263 //do nothing (parent == 0) no parent exists
265 }else if (synonymMarkers
.contains(nameStatus
)){
266 //add synonym relationship
267 acceptedTaxon
= parentTaxon
;
269 Synonym synonym
= CdmBase
.deproxy(taxonBase
,Synonym
.class);
270 if (acceptedTaxon
== null){
271 String message
= "Accepted/valid taxon could not be found. Please check referential integrity.";
272 fireWarningEvent(message
, state
, 8);
274 acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.SYNONYM_OF());
275 getTaxonService().saveOrUpdate(acceptedTaxon
);
277 } catch (Exception e
) {
278 String message
= "Unhandled exception (%s) occurred during synonym import/update";
279 message
= String
.format(message
, e
.getMessage());
280 fireWarningEvent(message
, state
, 10);
281 state
.setUnsuccessfull();
284 acceptedTaxon
= null;
285 String message
= "Unhandled name status (%s)";
286 message
= String
.format(message
, nameStatus
);
287 fireWarningEvent(message
, state
, 8);
289 }else{//taxonNameStr is empty
290 //vernacular name case
291 acceptedTaxon
= parentTaxon
;
292 nameUsedInSource
= null;
296 if (acceptedTaxon
== null && (CdmUtils
.isNotEmpty(commonNameStr
) ||taxonDataHolder
.getFeatures().size() > 0 )){
297 String message
= "Accepted taxon could not be found. Can't add additional data (common names, descriptive data, ...) to taxon";
298 fireWarningEvent(message
, state
, 6);
301 if (CdmUtils
.isNotEmpty(commonNameStr
)){ // add common name to taxon
302 handleCommonName(state
, taxonNameStr
, commonNameStr
, acceptedTaxon
);
307 for (String imageUrl
: taxonDataHolder
.getImages()){
308 TaxonDescription td
= acceptedTaxon
.getImageGallery(true);
309 DescriptionElementBase mediaHolder
;
310 if (td
.getElements().size() != 0){
311 mediaHolder
= td
.getElements().iterator().next();
313 mediaHolder
= TextData
.NewInstance(Feature
.IMAGE());
314 td
.addElement(mediaHolder
);
317 Media media
= getImageMedia(imageUrl
, READ_MEDIA_DATA
, false);
318 mediaHolder
.addMedia(media
);
319 } catch (MalformedURLException e
) {
320 logger
.warn("Can't add media: " + e
.getMessage());
321 state
.setUnsuccessfull();
326 for (String tdwg
: taxonDataHolder
.getDistributions()){
327 TaxonDescription td
= this.getTaxonDescription(acceptedTaxon
, state
.getConfig().getSourceReference() ,false, true);
328 NamedArea area
= TdwgArea
.getAreaByTdwgAbbreviation(tdwg
);
330 area
= TdwgArea
.getAreaByTdwgLabel(tdwg
);
333 Distribution distribution
= Distribution
.NewInstance(area
, PresenceTerm
.PRESENT());
334 td
.addElement(distribution
);
336 String message
= "TDWG area could not be recognized: " + tdwg
;
337 logger
.warn(message
);
338 state
.setUnsuccessfull();
343 handleFeatures(state
, taxonDataHolder
, acceptedTaxon
, nameUsedInSource
);
345 } catch (Exception e
) {
354 * @param taxonDataHolder
355 * @param acceptedTaxon
357 private void handleFeatures(TaxonExcelImportState state
, NormalExplicitRow taxonDataHolder
, Taxon acceptedTaxon
, TaxonNameBase nameUsedInSource
) {
359 for (UUID featureUuid
: taxonDataHolder
.getFeatures()){
360 Feature feature
= getFeature(state
, featureUuid
);
361 List
<String
> textList
= taxonDataHolder
.getFeatureTexts(featureUuid
);
362 List
<String
> languageList
= taxonDataHolder
.getFeatureLanguages(featureUuid
);
364 for (int i
= 0; i
< textList
.size(); i
++){
365 String featureText
= textList
.get(i
);
366 String featureLanguage
= languageList
== null ?
null :languageList
.get(i
);
367 Language language
= getFeatureLanguage(featureLanguage
, state
);
369 TaxonDescription td
= this.getTaxonDescription(acceptedTaxon
, state
.getConfig().getSourceReference() ,false, true);
370 TextData textData
= TextData
.NewInstance(feature
);
371 textData
.putText(language
, featureText
);
372 td
.addElement(textData
);
374 SourceDataHolder sourceDataHolder
= taxonDataHolder
.getFeatureTextReferences(featureUuid
, i
);
375 List
<Map
<SourceType
, String
>> sourceList
= sourceDataHolder
.getSources();
376 for (Map
<SourceType
, String
> sourceMap
: sourceList
){
379 Reference
<?
> ref
= ReferenceFactory
.newGeneric();
380 boolean refExists
= false; //in case none of the ref fields exists, the ref should not be added
381 for (SourceType type
: sourceMap
.keySet()){
382 String value
= sourceMap
.get(type
);
383 if (type
.equals(SourceType
.Author
)){
384 TeamOrPersonBase
<?
> author
= getAuthorAccordingToConfig(value
, state
);
385 ref
.setAuthorTeam(author
);
386 }else if (type
.equals(SourceType
.Title
)) {
388 }else if (type
.equals(SourceType
.Year
)) {
389 ref
.setDatePublished(TimePeriod
.parseString(value
));
390 }else if (type
.equals(SourceType
.RefExtension
)) {
391 ExtensionType extensionType
= getExtensionType(state
, uuidRefExtension
, "RefExtension", "Reference Extension", "RefExt.");
392 Extension extension
= Extension
.NewInstance(ref
, value
, extensionType
);
396 DescriptionElementSource source
= DescriptionElementSource
.NewInstance(OriginalSourceType
.PrimaryTaxonomicSource
);
398 ref
= getReferenceAccordingToConfig(ref
, state
);
399 source
.setCitation(ref
);
400 source
.setNameUsedInSource(nameUsedInSource
);
402 textData
.addSource(source
);
408 private Map
<String
, UUID
> referenceMapping
= new HashMap
<String
, UUID
>();
409 private Map
<UUID
, Reference
> referenceStore
= new HashMap
<UUID
, Reference
>();
411 private Reference
getReferenceAccordingToConfig(Reference value
, TaxonExcelImportState state
) {
412 Reference result
= null;
413 String titleCache
= value
.getTitleCache();
414 UUID referenceUuid
= referenceMapping
.get(titleCache
);
415 if (referenceUuid
!= null){
416 result
= referenceStore
.get(referenceUuid
);
420 referenceStore
.put(result
.getUuid(), result
);
422 if (referenceUuid
== null){
423 referenceMapping
.put(titleCache
, result
.getUuid());
429 private Map
<String
, UUID
> authorMapping
= new HashMap
<String
, UUID
>();
430 private Map
<UUID
, TeamOrPersonBase
> authorStore
= new HashMap
<UUID
, TeamOrPersonBase
>();
432 private TeamOrPersonBase
getAuthorAccordingToConfig(String value
, TaxonExcelImportState state
) {
433 TeamOrPersonBase result
= null;
434 UUID authorUuid
= authorMapping
.get(value
);
435 if (authorUuid
!= null){
436 result
= authorStore
.get(authorUuid
);
440 TeamOrPersonBase author
= Team
.NewInstance();
441 author
.setTitleCache(value
, true);
443 authorStore
.put(result
.getUuid(), result
);
445 if (authorUuid
== null){
446 authorMapping
.put(value
, result
.getUuid());
452 private Map
<String
, UUID
> languageMapping
= new HashMap
<String
, UUID
>();
454 private Language
getFeatureLanguage(String featureLanguage
, TaxonExcelImportState state
) {
455 if (StringUtils
.isBlank(featureLanguage
)){
458 UUID languageUuid
= languageMapping
.get(featureLanguage
);
459 if (languageUuid
== null){
460 Language result
= getTermService().getLanguageByIso(featureLanguage
);
461 languageUuid
= result
.getUuid();
462 languageMapping
.put(featureLanguage
, languageUuid
);
464 Language result
= getLanguage(state
, languageUuid
, null, null, null);
471 * @param taxonNameStr
472 * @param commonNameStr
475 private void handleCommonName(TaxonExcelImportState state
,
476 String taxonNameStr
, String commonNameStr
, Taxon acceptedTaxon
) {
477 Language language
= getTermService().getLanguageByIso(state
.getCurrentRow().getLanguage());
478 if (language
== null && CdmUtils
.isNotEmpty(state
.getCurrentRow().getLanguage()) ){
479 String error
="Language is null but shouldn't";
481 throw new IllegalArgumentException(error
);
483 CommonTaxonName commonTaxonName
= CommonTaxonName
.NewInstance(commonNameStr
, language
);
485 TaxonDescription taxonDescription
= getTaxonDescription(acceptedTaxon
, false, true);
486 taxonDescription
.addElement(commonTaxonName
);
487 logger
.info("Common name " + commonNameStr
+ " added to " + acceptedTaxon
.getTitleCache());
488 } catch (ClassCastException ex
) {
489 logger
.error(taxonNameStr
+ " is not a taxon instance.");
497 * @param taxonNameStr
502 private TaxonBase
createTaxon(TaxonExcelImportState state
, Rank rank
,
503 String taxonNameStr
, String authorStr
, String nameStatus
) {
504 // Create the taxon name object depending on the setting of the nomenclatural code
505 // in the configurator (botanical code, zoological code, etc.)
506 if (StringUtils
.isBlank(taxonNameStr
)){
509 NomenclaturalCode nc
= getConfigurator().getNomenclaturalCode();
511 TaxonBase taxonBase
= null;
513 String titleCache
= CdmUtils
.concat(" ", taxonNameStr
, authorStr
);
514 if (! synonymMarkers
.contains(nameStatus
) && state
.getConfig().isDoMatchTaxa()){
515 titleCache
= CdmUtils
.concat(" ", taxonNameStr
, authorStr
);
516 taxonBase
= getTaxonService().findBestMatchingTaxon(titleCache
);
518 taxonBase
= getTaxonService().findBestMatchingSynonym(titleCache
);
519 if (taxonBase
!= null){
520 logger
.info("Matching taxon/synonym found for " + titleCache
);
523 if (taxonBase
!= null){
524 logger
.info("Matching taxon/synonym found for " + titleCache
);
526 taxonBase
= createTaxon(state
, rank
, taxonNameStr
, authorStr
, nameStatus
, nc
);
537 * @param taxonNameStr
543 private TaxonBase
<?
> createTaxon(TaxonExcelImportState state
, Rank rank
, String taxonNameStr
,
544 String authorStr
, String nameStatus
, NomenclaturalCode nc
) {
545 TaxonBase
<?
> taxonBase
;
546 NonViralName
<?
> taxonNameBase
= null;
547 if (nc
== NomenclaturalCode
.ICVCN
){
548 logger
.warn("ICVCN not yet supported");
551 taxonNameBase
=(NonViralName
) nc
.getNewTaxonNameInstance(rank
);
552 //NonViralName nonViralName = (NonViralName)taxonNameBase;
553 NonViralNameParserImpl parser
= NonViralNameParserImpl
.NewInstance();
554 taxonNameBase
= parser
.parseFullName(taxonNameStr
, nc
, rank
);
556 taxonNameBase
.setNameCache(taxonNameStr
);
559 if (CdmUtils
.isNotEmpty(authorStr
)) {
561 parser
.parseAuthors(taxonNameBase
, authorStr
);
562 } catch (StringNotParsableException e
) {
563 taxonNameBase
.setAuthorshipCache(authorStr
);
569 Reference
<?
> sec
= state
.getConfig().getSourceReference();
571 nameStatus
= CdmUtils
.Nz(nameStatus
).trim().toLowerCase();
572 if (validMarkers
.contains(nameStatus
)){
573 taxonBase
= Taxon
.NewInstance(taxonNameBase
, sec
);
574 }else if (synonymMarkers
.contains(nameStatus
)){
575 taxonBase
= Synonym
.NewInstance(taxonNameBase
, sec
);
577 Taxon taxon
= Taxon
.NewInstance(taxonNameBase
, sec
);
578 taxon
.setTaxonStatusUnknown(true);
588 //TODO implementation must be improved when matching of taxon names with existing names is implemented
589 //=> the assumption that the only description is the description added by this import
591 private TaxonNameDescription
getNameDescription(TaxonNameBase
<?
,?
> name
) {
592 Set
<TaxonNameDescription
> descriptions
= name
.getDescriptions();
593 if (descriptions
.size()>1){
594 throw new IllegalStateException("Implementation does not yet support names with multiple descriptions");
595 }else if (descriptions
.size()==1){
596 return descriptions
.iterator().next();
598 return TaxonNameDescription
.NewInstance(name
);
602 private void makeParent(TaxonExcelImportState state
, Taxon parentTaxon
, Taxon childTaxon
, Reference citation
, String microCitation
){
603 Reference sec
= state
.getConfig().getSourceReference();
605 // Reference sec = parentTaxon.getSec();
606 Classification tree
= state
.getTree(sec
);
608 tree
= makeTree(state
, sec
);
610 if (sec
.equals(childTaxon
.getSec())){
611 boolean success
= (null != tree
.addParentChild(parentTaxon
, childTaxon
, citation
, microCitation
));
612 if (success
== false){
613 state
.setUnsuccessfull();
616 logger
.warn("No relationship added for child " + childTaxon
.getTitleCache());
623 * @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#createDataHolderRow()
626 protected NormalExplicitRow
createDataHolderRow() {
627 return new NormalExplicitRow();
633 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
636 protected boolean doCheck(TaxonExcelImportState state
) {
637 logger
.warn("DoCheck not yet implemented for NormalExplicitImport");
642 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
645 protected boolean isIgnore(TaxonExcelImportState state
) {