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
.tcsxml
.in
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Collection
;
14 import java
.util
.List
;
16 import org
.apache
.commons
.lang
.StringUtils
;
17 import org
.apache
.log4j
.Logger
;
18 import org
.jdom
.Element
;
19 import org
.jdom
.Namespace
;
20 import org
.springframework
.stereotype
.Component
;
22 import eu
.etaxonomy
.cdm
.common
.ResultWrapper
;
23 import eu
.etaxonomy
.cdm
.common
.XmlHelp
;
24 import eu
.etaxonomy
.cdm
.io
.common
.ICdmIO
;
25 import eu
.etaxonomy
.cdm
.io
.common
.ImportHelper
;
26 import eu
.etaxonomy
.cdm
.io
.common
.MapWrapper
;
27 import eu
.etaxonomy
.cdm
.io
.tcsxml
.TcsXmlTransformer
;
28 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
29 import eu
.etaxonomy
.cdm
.model
.agent
.Person
;
30 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
31 import eu
.etaxonomy
.cdm
.model
.name
.CultivarPlantName
;
32 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
33 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
34 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
35 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
36 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
37 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
38 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
39 import eu
.etaxonomy
.cdm
.strategy
.exceptions
.UnknownCdmTypeException
;
41 @Component("tcsXmlTaxonNameIO")
42 public class TcsXmlTaxonNameImport
extends TcsXmlImportBase
implements ICdmIO
<TcsXmlImportState
> {
43 private static final Logger logger
= Logger
.getLogger(TcsXmlTaxonNameImport
.class);
45 private static int modCount
= 5000;
47 public TcsXmlTaxonNameImport(){
52 public boolean doCheck(TcsXmlImportState state
){
53 boolean result
= true;
54 logger
.warn("BasionymRelations not yet implemented");
55 logger
.warn("Checking for TaxonNames not yet implemented");
56 //result &= checkArticlesWithoutJournal(tcsConfig);
57 //result &= checkPartOfJournal(tcsConfig);
62 //@SuppressWarnings("unchecked")
64 public boolean doInvoke(TcsXmlImportState state
){
66 logger
.info("start make TaxonNames ...");
67 MapWrapper
<Person
> authorMap
= (MapWrapper
<Person
>)state
.getStore(ICdmIO
.TEAM_STORE
);
68 MapWrapper
<TaxonNameBase
> taxonNameMap
= (MapWrapper
<TaxonNameBase
>)state
.getStore(ICdmIO
.TAXONNAME_STORE
);
69 MapWrapper
<Reference
> referenceMap
= (MapWrapper
<Reference
>)state
.getStore(ICdmIO
.REFERENCE_STORE
);
71 ResultWrapper
<Boolean
> success
= ResultWrapper
.NewInstance(true);
74 String idNamespace
= "TaxonName";
76 TcsXmlImportConfigurator config
= state
.getConfig();
77 Element elDataSet
= getDataSetElement(config
);
78 Namespace tcsNamespace
= config
.getTcsXmlNamespace();
80 childName
= "TaxonNames";
82 Element elTaxonNames
= XmlHelp
.getSingleChildElement(success
, elDataSet
, childName
, tcsNamespace
, obligatory
);
84 String tcsElementName
= "TaxonName";
85 List
<Element
> elTaxonNameList
= (List
<Element
>)elTaxonNames
.getChildren(tcsElementName
, tcsNamespace
);
89 for (Element elTaxonName
: elTaxonNameList
){
90 if ((++i
% modCount
) == 0){ logger
.info("Names handled: " + (i
-1));}
91 List
<String
> elementList
= new ArrayList
<String
>();
93 //create TaxonName element
94 String strId
= elTaxonName
.getAttributeValue("id");
95 String strNomenclaturalCode
= elTaxonName
.getAttributeValue("nomenclaturalCode");
99 Element elRank
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
100 Rank rank
= makeRank(elRank
);
101 elementList
.add(childName
.toString());
105 TaxonNameBase
<?
,?
> nameBase
;
106 NomenclaturalCode nomCode
= TcsXmlTransformer
.nomCodeString2NomCode(strNomenclaturalCode
);
107 if (nomCode
!= null){
108 nameBase
= nomCode
.getNewTaxonNameInstance(rank
);
110 nameBase
= NonViralName
.NewInstance(rank
);
112 childName
= "Simple";
114 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
115 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
116 nameBase
.setTitleCache(simple
, false);
117 elementList
.add(childName
.toString());
119 childName
= "CanonicalName";
121 Element elCanonicalName
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
122 makeCanonicalName(nameBase
, elCanonicalName
, taxonNameMap
, success
);
123 elementList
.add(childName
.toString());
125 childName
= "CanonicalAuthorship";
127 Element elCanonicalAuthorship
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
128 makeCanonicalAuthorship(nameBase
, elCanonicalAuthorship
, authorMap
, success
);
129 elementList
.add(childName
.toString());
131 childName
= "PublishedIn";
133 Element elPublishedIn
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
134 makePublishedIn(nameBase
, elPublishedIn
, referenceMap
, success
);
135 elementList
.add(childName
.toString());
139 Element elYear
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
140 makeYear(nameBase
, elYear
, success
);
141 elementList
.add(childName
.toString());
143 childName
= "MicroReference";
145 Element elMicroReference
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
146 makeMicroReference(nameBase
, elMicroReference
, success
);
147 elementList
.add(childName
.toString());
149 childName
= "Typification";
151 Element elTypification
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
152 makeTypification(nameBase
, elTypification
, success
);
153 elementList
.add(childName
.toString());
155 childName
= "PublicationStatus";
157 Element elPublicationStatus
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
158 makePublicationStatus(nameBase
, elPublicationStatus
, success
);
159 elementList
.add(childName
.toString());
161 childName
= "ProviderLink";
163 Element elProviderLink
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
164 makeProviderLink(nameBase
, elProviderLink
, success
);
165 elementList
.add(childName
.toString());
167 childName
= "ProviderSpecificData";
169 Element elProviderSpecificData
= XmlHelp
.getSingleChildElement(success
, elTaxonName
, childName
, tcsNamespace
, obligatory
);
170 makeProviderSpecificData(nameBase
, elProviderSpecificData
, success
);
171 elementList
.add(childName
.toString());
174 ImportHelper
.setOriginalSource(nameBase
, config
.getSourceReference(), strId
, idNamespace
);
176 taxonNameMap
.put(strId
, nameBase
);
178 } catch (UnknownCdmTypeException e
) {
179 logger
.warn("Name with id " + strId
+ " has unknown nomenclatural code.");
180 success
.setValue(false);
183 logger
.info(i
+ " names handled");
184 Collection
<?
extends TaxonNameBase
> col
= taxonNameMap
.objects();
185 getNameService().save((Collection
)col
);
187 logger
.info("end makeTaxonNames ...");
188 return success
.getValue();
193 * Returns the rank represented by the rank element.<br>
194 * Returns <code>null</code> if the element is null.<br>
195 * Returns <code>null</code> if the code and the text are both either empty or do not exists.<br>
196 * Returns the rank represented by the code attribute, if the code attribute is not empty and could be resolved.<br>
197 * If the code could not be resolved it returns the rank represented most likely by the elements text.<br>
198 * Returns UNKNOWN_RANK if code attribute and element text could not be resolved.
199 * @param elRank tcs rank element
202 protected static Rank
makeRank(Element elRank
){
207 String strRankCode
= elRank
.getAttributeValue("code");
208 String strRankString
= elRank
.getTextNormalize();
209 if ( StringUtils
.isBlank(strRankCode
) && StringUtils
.isBlank(strRankString
)){
213 Rank codeRank
= null;
215 codeRank
= TcsXmlTransformer
.rankCode2Rank(strRankCode
);
216 } catch (UnknownCdmTypeException e1
) {
217 codeRank
= Rank
.UNKNOWN_RANK();
219 Rank stringRank
= null;
221 boolean useUnknown
= true;
222 stringRank
= Rank
.getRankByNameOrAbbreviation(strRankString
, useUnknown
);
223 } catch (UnknownCdmTypeException e1
) {
224 //does not happen because of useUnknown = true
228 if ( (codeRank
!= null) && ! codeRank
.equals(Rank
.UNKNOWN_RANK())){
230 if (! codeRank
.equals(stringRank
) && ! stringRank
.equals(Rank
.UNKNOWN_RANK())){
231 logger
.warn("code rank and string rank are unequal. code: " + codeRank
.getLabel() + " <-> string: " + stringRank
.getLabel());
234 //codeRank does not exist
237 logger
.warn("string rank used, because code rank does not exist or was not recognized: " + stringRank
.getLabel());
242 private void makeCanonicalName(TaxonNameBase name
, Element elCanonicalName
, MapWrapper
<TaxonNameBase
> taxonNameMap
, ResultWrapper
<Boolean
> success
){
243 boolean cacheProtected
= false;
245 if (elCanonicalName
== null){
248 Namespace ns
= elCanonicalName
.getNamespace();
250 String childName
= "Simple";
251 boolean obligatory
= true;
252 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
253 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
254 name
.setFullTitleCache(simple
, cacheProtected
);
256 if (name
instanceof NonViralName
<?
>){
257 NonViralName
<?
> nonViralName
= (NonViralName
<?
>)name
;
258 childName
= "Uninomial";
260 Element elUninomial
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
261 String uninomial
= (elUninomial
== null)?
"" : elUninomial
.getTextNormalize();
262 if (StringUtils
.isNotBlank(uninomial
)){
263 nonViralName
.setGenusOrUninomial(uninomial
);
264 if (nonViralName
.getRank() != null && nonViralName
.getRank().isLower(Rank
.GENUS())){ // TODO check
265 logger
.warn("Name " + simple
+ " lower then 'genus' but has a canonical name part 'Uninomial'.");
268 testNoMoreElements();
272 Element elGenus
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
273 if (elGenus
!= null){
274 //TODO do Attributes reference
275 makeGenusReferenceType(name
, elGenus
, taxonNameMap
, success
);
276 String genus
= elGenus
.getTextNormalize();
277 if (StringUtils
.isNotBlank(genus
)){
278 nonViralName
.setGenusOrUninomial(genus
);
279 if (nonViralName
.getRank() != null && ! nonViralName
.getRank().isLower(Rank
.GENUS() )){ // TODO check
280 logger
.warn("Name " + simple
+ " is not lower then 'genus' but has canonical name part 'Genus'.");
285 childName
= "InfragenericEpithet";
287 Element elInfrageneric
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
288 String infraGenericEpithet
= (elInfrageneric
== null)?
"" : elInfrageneric
.getTextNormalize();
289 if (! infraGenericEpithet
.trim().equals("")){
290 nonViralName
.setInfraGenericEpithet(infraGenericEpithet
);
291 if (nonViralName
.getRank() != null && ! name
.getRank().isInfraGeneric()){
292 logger
.warn("Name " + simple
+ " is not infra generic but has canonical name part 'InfragenericEpithet'.");
295 testNoMoreElements();
297 childName
= "SpecificEpithet";
299 Element elSpecificEpithet
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
300 String specificEpithet
= (elSpecificEpithet
== null)?
"" : elSpecificEpithet
.getTextNormalize();
301 if (! specificEpithet
.trim().equals("")){
302 nonViralName
.setSpecificEpithet(specificEpithet
);
303 if (nonViralName
.getRank() != null && name
.getRank().isHigher(Rank
.SPECIES()) ){
304 logger
.warn("Name " + simple
+ " is not species or below but has canonical name part 'SpecificEpithet'.");
307 testNoMoreElements();
309 childName
= "InfraspecificEpithet";
311 Element elInfraspecificEpithet
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
312 String infraspecificEpithet
= (elInfraspecificEpithet
== null)?
"" : elInfraspecificEpithet
.getTextNormalize();
313 if (! infraspecificEpithet
.trim().equals("")){
314 nonViralName
.setInfraSpecificEpithet(infraspecificEpithet
);
315 if (nonViralName
.getRank() != null && ! name
.isInfraSpecific() ){
316 logger
.warn("Name " + simple
+ " is not infraspecific but has canonical name part 'InfraspecificEpithet'.");
319 testNoMoreElements();
323 //logger.warn("Non NonViralNames not yet supported by makeCanonicalName");
327 childName
= "CultivarNameGroup";
329 Element elCultivarNameGroup
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
330 String cultivarNameGroup
= (elCultivarNameGroup
== null)?
"" : elCultivarNameGroup
.getTextNormalize();
331 if (! "".equals(cultivarNameGroup
.trim())){
332 if (name
instanceof CultivarPlantName
){
335 logger
.warn("Non cultivar name has 'cultivar name group' element. Omitted");
341 protected void testNoMoreElements(){
343 //logger.info("testNoMoreElements Not yet implemented");
346 private void makeCultivarName(){
348 //logger.warn("'makeCultivarName' Not yet implemented");
351 private void makeGenusReferenceType(TaxonNameBase name
, Element elGenus
, MapWrapper
<TaxonNameBase
> taxonNameMap
, ResultWrapper
<Boolean
> success
){
352 if(name
instanceof NonViralName
){
353 NonViralName nonViralName
= (NonViralName
)name
;
354 if (elGenus
!= null && name
!= null){
355 TaxonNameBase genusReferenceName
;
357 Class
<?
extends NonViralName
> clazz
= NonViralName
.class;
358 genusReferenceName
= makeReferenceType(elGenus
, clazz
, taxonNameMap
, success
);
359 NonViralName nvGenusReference
= (NonViralName
)genusReferenceName
;
360 //Genus is stored either in Genus part (if ref) or in titleCache (if plain text)
361 String genus
= nvGenusReference
.getGenusOrUninomial()!= null ? nvGenusReference
.getGenusOrUninomial(): genusReferenceName
.getTitleCache();
362 nonViralName
.setGenusOrUninomial(genus
);
364 logger
.warn("Missing Genus information");
367 //TODO (can be changed if Viral Name also has Genus in future
368 //logger.warn("Genus ref type for Viral Name not implemented yet");
374 @SuppressWarnings("unchecked")
375 private INomenclaturalAuthor
makeNameCitation(Element elNameCitation
, MapWrapper
<Person
> authorMap
, ResultWrapper
<Boolean
> success
){
376 INomenclaturalAuthor result
= null;
379 if (elNameCitation
!= null){
380 Namespace ns
= elNameCitation
.getNamespace();
382 childName
= "Authors";
384 Element elAuthors
= XmlHelp
.getSingleChildElement(success
, elNameCitation
, childName
, ns
, obligatory
);
385 testNoMoreElements();
387 if (elAuthors
!= null){
388 childName
= "AgentName";
389 List
<Element
> elAgentList
= elAuthors
.getChildren(childName
, ns
);
390 Team team
= Team
.NewInstance();
392 if (elAgentList
.size() > 1){
393 for(Element elAgent
: elAgentList
){
394 Person teamMember
= makeAgent(elAgent
, ns
, authorMap
, success
);
395 team
.addTeamMember(teamMember
);
397 }else if(elAgentList
.size() == 1){
398 result
= makeAgent(elAgentList
.get(0), ns
, authorMap
, success
);
401 childName
= "Simple";
403 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elNameCitation
, childName
, ns
, obligatory
);
404 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
405 result
= Team
.NewInstance();
406 result
.setNomenclaturalTitle(simple
);
412 private Person
makeAgent(Element elAgentName
, Namespace ns
, MapWrapper
<Person
> agentMap
, ResultWrapper
<Boolean
> success
){
413 Person result
= null;
414 if (elAgentName
!= null){
415 String authorTitle
= elAgentName
.getTextNormalize();
416 result
= Person
.NewTitledInstance(authorTitle
);
417 Class
<?
extends Person
> clazz
= Person
.class;
418 result
= makeReferenceType(elAgentName
, clazz
, agentMap
, success
);
425 private void makeCanonicalAuthorship(TaxonNameBase name
, Element elCanonicalAuthorship
, MapWrapper
<Person
> authorMap
, ResultWrapper
<Boolean
> success
){
426 if (elCanonicalAuthorship
!= null){
427 Namespace ns
= elCanonicalAuthorship
.getNamespace();
429 if (name
instanceof NonViralName
){
430 NonViralName nonViralName
= (NonViralName
)name
;
432 String childName
= "Simple";
433 boolean obligatory
= true;
434 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
435 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
437 //logger.warn("authorship cache cache protected not yet implemented");
438 //nonViralName.setAuthorshipCache(simple, cacheProtected);
440 childName
= "Authorship";
442 Element elAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
443 INomenclaturalAuthor author
= makeNameCitation(elAuthorship
, authorMap
, success
);
444 nonViralName
.setCombinationAuthorTeam(author
);
445 testNoMoreElements();
447 childName
= "BasionymAuthorship";
449 Element elBasionymAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
450 INomenclaturalAuthor basionymAuthor
= makeNameCitation(elBasionymAuthorship
, authorMap
, success
);
451 nonViralName
.setBasionymAuthorTeam(basionymAuthor
);
452 testNoMoreElements();
454 childName
= "CombinationAuthorship";
456 Element elCombinationAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
457 INomenclaturalAuthor combinationAuthor
= makeNameCitation(elCombinationAuthorship
, authorMap
,success
);
458 if (combinationAuthor
!= null){
459 nonViralName
.setCombinationAuthorTeam(combinationAuthor
);
461 testNoMoreElements();
463 if (elAuthorship
!= null && (elBasionymAuthorship
!= null || elCombinationAuthorship
!= null) ){
464 logger
.warn("Authorship and (BasionymAuthorship or CombinationAuthorship) must not exist at the same time in CanonicalAuthorship");
465 success
.setValue(false);
472 private void makePublishedIn(TaxonNameBase name
, Element elPublishedIn
, MapWrapper
<Reference
> referenceMap
, ResultWrapper
<Boolean
> success
){
473 if (elPublishedIn
!= null && name
!= null){
474 Class
<?
extends Reference
> clazz
= Reference
.class;
475 Reference ref
= makeReferenceType(elPublishedIn
, clazz
, referenceMap
, success
);
476 if (ref
instanceof INomenclaturalReference
){
477 name
.setNomenclaturalReference(ref
);
479 logger
.warn("Reference is not of type INomenclaturalReference and could not be added to the name " + name
.getTitleCache());
481 }else if (name
== null){
482 logger
.warn("TaxonName must not be 'null'");
483 success
.setValue(false);
488 private void makeYear(TaxonNameBase name
, Element elYear
, ResultWrapper
<Boolean
> success
){
490 String year
= elYear
.getTextNormalize();
491 if (name
instanceof ZoologicalName
){
492 ((ZoologicalName
)name
).setPublicationYear(getIntegerYear(year
));
494 logger
.warn("Year can be set only for a zoological name");
499 private Integer
getIntegerYear(String year
){
501 Integer result
= Integer
.valueOf(year
);
503 } catch (NumberFormatException e
) {
504 logger
.warn("Year string could not be parsed. Set = 9999 instead");
510 private void makeMicroReference(TaxonNameBase name
, Element elMicroReference
, ResultWrapper
<Boolean
> success
){
511 if (elMicroReference
!= null){
512 String microReference
= elMicroReference
.getTextNormalize();
513 name
.setNomenclaturalMicroReference(microReference
);
518 private void makeTypification(TaxonNameBase name
, Element elTypifiacation
, ResultWrapper
<Boolean
> success
){
519 if (elTypifiacation
!= null){
520 //logger.warn("makeTypification not yet implemented");
521 //success.setValue(false);
526 private void makePublicationStatus(TaxonNameBase name
, Element elPublicationStatus
, ResultWrapper
<Boolean
> success
){
529 if (elPublicationStatus
!= null){
530 //logger.warn("makePublicationStatus not yet implemented");
531 //success.setValue(false);
535 private void makeProviderLink(TaxonNameBase name
, Element elProviderLink
, ResultWrapper
<Boolean
> success
){
536 if (elProviderLink
!= null){
537 //logger.warn("makeProviderLink not yet implemented");
538 //success.setValue(false);
543 private void makeProviderSpecificData(TaxonNameBase name
, Element elProviderSpecificData
, ResultWrapper
<Boolean
> success
){
544 if (elProviderSpecificData
!= null){
545 //logger.warn("makeProviderSpecificData not yet implemented");
546 //success.setValue(false);
552 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
554 protected boolean isIgnore(TcsXmlImportState state
){
555 return ! state
.getConfig().isDoTaxonNames();