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
.ReferenceBase
;
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
<ReferenceBase
> referenceMap
= (MapWrapper
<ReferenceBase
>)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 (strRankCode
== null || "".equals(strRankCode
.trim()) &&
210 strRankString
== null || "".equals(strRankString
.trim())
215 Rank codeRank
= null;
217 codeRank
= TcsXmlTransformer
.rankCode2Rank(strRankCode
);
218 } catch (UnknownCdmTypeException e1
) {
219 codeRank
= Rank
.UNKNOWN_RANK();
221 Rank stringRank
= null;
223 boolean useUnknown
= true;
224 stringRank
= Rank
.getRankByNameOrAbbreviation(strRankString
, useUnknown
);
225 } catch (UnknownCdmTypeException e1
) {
226 //does not happen because of useUnknown = true
230 if (! (codeRank
== null) && ! codeRank
.equals(Rank
.UNKNOWN_RANK())){
232 if (! codeRank
.equals(stringRank
) && ! stringRank
.equals(Rank
.UNKNOWN_RANK())){
233 logger
.warn("code rank and string rank are unequal. code: " + codeRank
.getLabel() + stringRank
.getLabel());
236 //codeRank does not exist
239 logger
.warn("string rank used, because code rank does not exist or was not recognized: " + stringRank
.getLabel());
244 private void makeCanonicalName(TaxonNameBase name
, Element elCanonicalName
, MapWrapper
<TaxonNameBase
> taxonNameMap
, ResultWrapper
<Boolean
> success
){
245 boolean cacheProtected
= false;
247 if (elCanonicalName
== null){
250 Namespace ns
= elCanonicalName
.getNamespace();
252 String childName
= "Simple";
253 boolean obligatory
= true;
254 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
255 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
256 name
.setFullTitleCache(simple
, cacheProtected
);
258 if (name
instanceof NonViralName
<?
>){
259 NonViralName
<?
> nonViralName
= (NonViralName
<?
>)name
;
260 childName
= "Uninomial";
262 Element elUninomial
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
263 String uninomial
= (elUninomial
== null)?
"" : elUninomial
.getTextNormalize();
264 if (StringUtils
.isNotBlank(uninomial
)){
265 nonViralName
.setGenusOrUninomial(uninomial
);
266 if (nonViralName
.getRank() != null && nonViralName
.getRank().isLower(Rank
.GENUS())){ // TODO check
267 logger
.warn("Name " + simple
+ " lower then 'genus' but has a canonical name part 'Uninomial'.");
270 testNoMoreElements();
274 Element elGenus
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
275 if (elGenus
!= null){
276 //TODO do Attributes reference
277 makeGenusReferenceType(name
, elGenus
, taxonNameMap
, success
);
278 String genus
= elGenus
.getTextNormalize();
279 if (StringUtils
.isNotBlank(genus
)){
280 nonViralName
.setGenusOrUninomial(genus
);
281 if (nonViralName
.getRank() != null && ! nonViralName
.getRank().isLower(Rank
.GENUS() )){ // TODO check
282 logger
.warn("Name " + simple
+ " is not lower then 'genus' but has canonical name part 'Genus'.");
287 childName
= "InfragenericEpithet";
289 Element elInfrageneric
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
290 String infraGenericEpithet
= (elInfrageneric
== null)?
"" : elInfrageneric
.getTextNormalize();
291 if (! infraGenericEpithet
.trim().equals("")){
292 nonViralName
.setInfraGenericEpithet(infraGenericEpithet
);
293 if (nonViralName
.getRank() != null && ! name
.getRank().isInfraGeneric()){
294 logger
.warn("Name " + simple
+ " is not infra generic but has canonical name part 'InfragenericEpithet'.");
297 testNoMoreElements();
299 childName
= "SpecificEpithet";
301 Element elSpecificEpithet
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
302 String specificEpithet
= (elSpecificEpithet
== null)?
"" : elSpecificEpithet
.getTextNormalize();
303 if (! specificEpithet
.trim().equals("")){
304 nonViralName
.setSpecificEpithet(specificEpithet
);
305 if (nonViralName
.getRank() != null && name
.getRank().isHigher(Rank
.SPECIES()) ){
306 logger
.warn("Name " + simple
+ " is not species or below but has canonical name part 'SpecificEpithet'.");
309 testNoMoreElements();
311 childName
= "InfraspecificEpithet";
313 Element elInfraspecificEpithet
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
314 String infraspecificEpithet
= (elInfraspecificEpithet
== null)?
"" : elInfraspecificEpithet
.getTextNormalize();
315 if (! infraspecificEpithet
.trim().equals("")){
316 nonViralName
.setInfraSpecificEpithet(infraspecificEpithet
);
317 if (nonViralName
.getRank() != null && ! name
.isInfraSpecific() ){
318 logger
.warn("Name " + simple
+ " is not infraspecific but has canonical name part 'InfraspecificEpithet'.");
321 testNoMoreElements();
325 //logger.warn("Non NonViralNames not yet supported by makeCanonicalName");
329 childName
= "CultivarNameGroup";
331 Element elCultivarNameGroup
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
332 String cultivarNameGroup
= (elCultivarNameGroup
== null)?
"" : elCultivarNameGroup
.getTextNormalize();
333 if (! "".equals(cultivarNameGroup
.trim())){
334 if (name
instanceof CultivarPlantName
){
337 logger
.warn("Non cultivar name has 'cultivar name group' element. Omitted");
343 protected void testNoMoreElements(){
345 //logger.info("testNoMoreElements Not yet implemented");
348 private void makeCultivarName(){
350 //logger.warn("'makeCultivarName' Not yet implemented");
353 private void makeGenusReferenceType(TaxonNameBase name
, Element elGenus
, MapWrapper
<TaxonNameBase
> taxonNameMap
, ResultWrapper
<Boolean
> success
){
354 if(name
instanceof NonViralName
){
355 NonViralName nonViralName
= (NonViralName
)name
;
356 if (elGenus
!= null && name
!= null){
357 TaxonNameBase genusReferenceName
;
359 Class
<?
extends NonViralName
> clazz
= NonViralName
.class;
360 genusReferenceName
= makeReferenceType(elGenus
, clazz
, taxonNameMap
, success
);
361 NonViralName nvGenusReference
= (NonViralName
)genusReferenceName
;
362 //Genus is stored either in Genus part (if ref) or in titleCache (if plain text)
363 String genus
= nvGenusReference
.getGenusOrUninomial()!= null ? nvGenusReference
.getGenusOrUninomial(): genusReferenceName
.getTitleCache();
364 nonViralName
.setGenusOrUninomial(genus
);
366 logger
.warn("Missing Genus information");
369 //TODO (can be changed if Viral Name also has Genus in future
370 //logger.warn("Genus ref type for Viral Name not implemented yet");
376 @SuppressWarnings("unchecked")
377 private INomenclaturalAuthor
makeNameCitation(Element elNameCitation
, MapWrapper
<Person
> authorMap
, ResultWrapper
<Boolean
> success
){
378 INomenclaturalAuthor result
= null;
381 if (elNameCitation
!= null){
382 Namespace ns
= elNameCitation
.getNamespace();
384 childName
= "Authors";
386 Element elAuthors
= XmlHelp
.getSingleChildElement(success
, elNameCitation
, childName
, ns
, obligatory
);
387 testNoMoreElements();
389 if (elAuthors
!= null){
390 childName
= "AgentName";
391 List
<Element
> elAgentList
= elAuthors
.getChildren(childName
, ns
);
392 Team team
= Team
.NewInstance();
394 if (elAgentList
.size() > 1){
395 for(Element elAgent
: elAgentList
){
396 Person teamMember
= makeAgent(elAgent
, ns
, authorMap
, success
);
397 team
.addTeamMember(teamMember
);
399 }else if(elAgentList
.size() == 1){
400 result
= makeAgent(elAgentList
.get(0), ns
, authorMap
, success
);
403 childName
= "Simple";
405 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elNameCitation
, childName
, ns
, obligatory
);
406 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
407 result
= Team
.NewInstance();
408 result
.setNomenclaturalTitle(simple
);
414 private Person
makeAgent(Element elAgentName
, Namespace ns
, MapWrapper
<Person
> agentMap
, ResultWrapper
<Boolean
> success
){
415 Person result
= null;
416 if (elAgentName
!= null){
417 String authorTitle
= elAgentName
.getTextNormalize();
418 result
= Person
.NewTitledInstance(authorTitle
);
419 Class
<?
extends Person
> clazz
= Person
.class;
420 result
= makeReferenceType(elAgentName
, clazz
, agentMap
, success
);
427 private void makeCanonicalAuthorship(TaxonNameBase name
, Element elCanonicalAuthorship
, MapWrapper
<Person
> authorMap
, ResultWrapper
<Boolean
> success
){
428 if (elCanonicalAuthorship
!= null){
429 Namespace ns
= elCanonicalAuthorship
.getNamespace();
431 if (name
instanceof NonViralName
){
432 NonViralName nonViralName
= (NonViralName
)name
;
434 String childName
= "Simple";
435 boolean obligatory
= true;
436 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
437 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
439 //logger.warn("authorship cache cache protected not yet implemented");
440 //nonViralName.setAuthorshipCache(simple, cacheProtected);
442 childName
= "Authorship";
444 Element elAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
445 INomenclaturalAuthor author
= makeNameCitation(elAuthorship
, authorMap
, success
);
446 nonViralName
.setCombinationAuthorTeam(author
);
447 testNoMoreElements();
449 childName
= "BasionymAuthorship";
451 Element elBasionymAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
452 INomenclaturalAuthor basionymAuthor
= makeNameCitation(elBasionymAuthorship
, authorMap
, success
);
453 nonViralName
.setBasionymAuthorTeam(basionymAuthor
);
454 testNoMoreElements();
456 childName
= "CombinationAuthorship";
458 Element elCombinationAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
459 INomenclaturalAuthor combinationAuthor
= makeNameCitation(elCombinationAuthorship
, authorMap
,success
);
460 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
<ReferenceBase
> referenceMap
, ResultWrapper
<Boolean
> success
){
473 if (elPublishedIn
!= null && name
!= null){
474 Class
<?
extends ReferenceBase
> clazz
= ReferenceBase
.class;
475 ReferenceBase 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();