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 void 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 if (!success
.getValue()){
189 state
.setUnsuccessfull();
197 * Returns the rank represented by the rank element.<br>
198 * Returns <code>null</code> if the element is null.<br>
199 * Returns <code>null</code> if the code and the text are both either empty or do not exists.<br>
200 * Returns the rank represented by the code attribute, if the code attribute is not empty and could be resolved.<br>
201 * If the code could not be resolved it returns the rank represented most likely by the elements text.<br>
202 * Returns UNKNOWN_RANK if code attribute and element text could not be resolved.
203 * @param elRank tcs rank element
206 protected static Rank
makeRank(Element elRank
){
211 String strRankCode
= elRank
.getAttributeValue("code");
212 String strRankString
= elRank
.getTextNormalize();
213 if ( StringUtils
.isBlank(strRankCode
) && StringUtils
.isBlank(strRankString
)){
217 Rank codeRank
= null;
219 codeRank
= TcsXmlTransformer
.rankCode2Rank(strRankCode
);
220 } catch (UnknownCdmTypeException e1
) {
221 codeRank
= Rank
.UNKNOWN_RANK();
223 Rank stringRank
= null;
225 boolean useUnknown
= true;
226 stringRank
= Rank
.getRankByNameOrIdInVoc(strRankString
, useUnknown
);
227 } catch (UnknownCdmTypeException e1
) {
228 //does not happen because of useUnknown = true
232 if ( (codeRank
!= null) && ! codeRank
.equals(Rank
.UNKNOWN_RANK())){
234 if (! codeRank
.equals(stringRank
) && ! stringRank
.equals(Rank
.UNKNOWN_RANK())){
235 logger
.warn("code rank and string rank are unequal. code: " + codeRank
.getLabel() + " <-> string: " + stringRank
.getLabel());
238 //codeRank does not exist
241 logger
.warn("string rank used, because code rank does not exist or was not recognized: " + stringRank
.getLabel());
246 private void makeCanonicalName(TaxonNameBase name
, Element elCanonicalName
, MapWrapper
<TaxonNameBase
> taxonNameMap
, ResultWrapper
<Boolean
> success
){
247 boolean cacheProtected
= false;
249 if (elCanonicalName
== null){
252 Namespace ns
= elCanonicalName
.getNamespace();
254 String childName
= "Simple";
255 boolean obligatory
= true;
256 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
257 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
258 name
.setFullTitleCache(simple
, cacheProtected
);
260 if (name
instanceof NonViralName
<?
>){
261 NonViralName
<?
> nonViralName
= (NonViralName
<?
>)name
;
262 childName
= "Uninomial";
264 Element elUninomial
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
265 String uninomial
= (elUninomial
== null)?
"" : elUninomial
.getTextNormalize();
266 if (StringUtils
.isNotBlank(uninomial
)){
267 nonViralName
.setGenusOrUninomial(uninomial
);
268 if (nonViralName
.getRank() != null && nonViralName
.getRank().isLower(Rank
.GENUS())){ // TODO check
269 logger
.warn("Name " + simple
+ " lower then 'genus' but has a canonical name part 'Uninomial'.");
272 testNoMoreElements();
276 Element elGenus
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
277 if (elGenus
!= null){
278 //TODO do Attributes reference
279 makeGenusReferenceType(name
, elGenus
, taxonNameMap
, success
);
280 String genus
= elGenus
.getTextNormalize();
281 if (StringUtils
.isNotBlank(genus
)){
282 nonViralName
.setGenusOrUninomial(genus
);
283 if (nonViralName
.getRank() != null && ! nonViralName
.getRank().isLower(Rank
.GENUS() )){ // TODO check
284 logger
.warn("Name " + simple
+ " is not lower then 'genus' but has canonical name part 'Genus'.");
289 childName
= "InfragenericEpithet";
291 Element elInfrageneric
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
292 String infraGenericEpithet
= (elInfrageneric
== null)?
"" : elInfrageneric
.getTextNormalize();
293 if (! infraGenericEpithet
.trim().equals("")){
294 nonViralName
.setInfraGenericEpithet(infraGenericEpithet
);
295 if (nonViralName
.getRank() != null && ! name
.getRank().isInfraGeneric()){
296 logger
.warn("Name " + simple
+ " is not infra generic but has canonical name part 'InfragenericEpithet'.");
299 testNoMoreElements();
301 childName
= "SpecificEpithet";
303 Element elSpecificEpithet
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
304 String specificEpithet
= (elSpecificEpithet
== null)?
"" : elSpecificEpithet
.getTextNormalize();
305 if (! specificEpithet
.trim().equals("")){
306 nonViralName
.setSpecificEpithet(specificEpithet
);
307 if (nonViralName
.getRank() != null && name
.getRank().isHigher(Rank
.SPECIES()) ){
308 logger
.warn("Name " + simple
+ " is not species or below but has canonical name part 'SpecificEpithet'.");
311 testNoMoreElements();
313 childName
= "InfraspecificEpithet";
315 Element elInfraspecificEpithet
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
316 String infraspecificEpithet
= (elInfraspecificEpithet
== null)?
"" : elInfraspecificEpithet
.getTextNormalize();
317 if (! infraspecificEpithet
.trim().equals("")){
318 nonViralName
.setInfraSpecificEpithet(infraspecificEpithet
);
319 if (nonViralName
.getRank() != null && ! name
.isInfraSpecific() ){
320 logger
.warn("Name " + simple
+ " is not infraspecific but has canonical name part 'InfraspecificEpithet'.");
323 testNoMoreElements();
327 //logger.warn("Non NonViralNames not yet supported by makeCanonicalName");
331 childName
= "CultivarNameGroup";
333 Element elCultivarNameGroup
= XmlHelp
.getSingleChildElement(success
, elCanonicalName
, childName
, ns
, obligatory
);
334 String cultivarNameGroup
= (elCultivarNameGroup
== null)?
"" : elCultivarNameGroup
.getTextNormalize();
335 if (! "".equals(cultivarNameGroup
.trim())){
336 if (name
instanceof CultivarPlantName
){
339 logger
.warn("Non cultivar name has 'cultivar name group' element. Omitted");
345 protected void testNoMoreElements(){
347 //logger.info("testNoMoreElements Not yet implemented");
350 private void makeCultivarName(){
352 //logger.warn("'makeCultivarName' Not yet implemented");
355 private void makeGenusReferenceType(TaxonNameBase name
, Element elGenus
, MapWrapper
<TaxonNameBase
> taxonNameMap
, ResultWrapper
<Boolean
> success
){
356 if(name
instanceof NonViralName
){
357 NonViralName nonViralName
= (NonViralName
)name
;
358 if (elGenus
!= null && name
!= null){
359 TaxonNameBase genusReferenceName
;
361 Class
<?
extends NonViralName
> clazz
= NonViralName
.class;
362 genusReferenceName
= makeReferenceType(elGenus
, clazz
, taxonNameMap
, success
);
363 NonViralName nvGenusReference
= (NonViralName
)genusReferenceName
;
364 //Genus is stored either in Genus part (if ref) or in titleCache (if plain text)
365 String genus
= nvGenusReference
.getGenusOrUninomial()!= null ? nvGenusReference
.getGenusOrUninomial(): genusReferenceName
.getTitleCache();
366 nonViralName
.setGenusOrUninomial(genus
);
368 logger
.warn("Missing Genus information");
371 //TODO (can be changed if Viral Name also has Genus in future
372 //logger.warn("Genus ref type for Viral Name not implemented yet");
378 @SuppressWarnings("unchecked")
379 private INomenclaturalAuthor
makeNameCitation(Element elNameCitation
, MapWrapper
<Person
> authorMap
, ResultWrapper
<Boolean
> success
){
380 INomenclaturalAuthor result
= null;
383 if (elNameCitation
!= null){
384 Namespace ns
= elNameCitation
.getNamespace();
386 childName
= "Authors";
388 Element elAuthors
= XmlHelp
.getSingleChildElement(success
, elNameCitation
, childName
, ns
, obligatory
);
389 testNoMoreElements();
391 if (elAuthors
!= null){
392 childName
= "AgentName";
393 List
<Element
> elAgentList
= elAuthors
.getChildren(childName
, ns
);
394 Team team
= Team
.NewInstance();
396 if (elAgentList
.size() > 1){
397 for(Element elAgent
: elAgentList
){
398 Person teamMember
= makeAgent(elAgent
, ns
, authorMap
, success
);
399 team
.addTeamMember(teamMember
);
401 }else if(elAgentList
.size() == 1){
402 result
= makeAgent(elAgentList
.get(0), ns
, authorMap
, success
);
405 childName
= "Simple";
407 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elNameCitation
, childName
, ns
, obligatory
);
408 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
409 result
= Team
.NewInstance();
410 result
.setNomenclaturalTitle(simple
);
416 private Person
makeAgent(Element elAgentName
, Namespace ns
, MapWrapper
<Person
> agentMap
, ResultWrapper
<Boolean
> success
){
417 Person result
= null;
418 if (elAgentName
!= null){
419 String authorTitle
= elAgentName
.getTextNormalize();
420 result
= Person
.NewTitledInstance(authorTitle
);
421 Class
<?
extends Person
> clazz
= Person
.class;
422 result
= makeReferenceType(elAgentName
, clazz
, agentMap
, success
);
429 private void makeCanonicalAuthorship(TaxonNameBase name
, Element elCanonicalAuthorship
, MapWrapper
<Person
> authorMap
, ResultWrapper
<Boolean
> success
){
430 if (elCanonicalAuthorship
!= null){
431 Namespace ns
= elCanonicalAuthorship
.getNamespace();
433 if (name
instanceof NonViralName
){
434 NonViralName nonViralName
= (NonViralName
)name
;
436 String childName
= "Simple";
437 boolean obligatory
= true;
438 Element elSimple
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
439 String simple
= (elSimple
== null)?
"" : elSimple
.getTextNormalize();
441 //logger.warn("authorship cache cache protected not yet implemented");
442 //nonViralName.setAuthorshipCache(simple, cacheProtected);
444 childName
= "Authorship";
446 Element elAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
447 INomenclaturalAuthor author
= makeNameCitation(elAuthorship
, authorMap
, success
);
448 nonViralName
.setCombinationAuthorTeam(author
);
449 testNoMoreElements();
451 childName
= "BasionymAuthorship";
453 Element elBasionymAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
454 INomenclaturalAuthor basionymAuthor
= makeNameCitation(elBasionymAuthorship
, authorMap
, success
);
455 nonViralName
.setBasionymAuthorTeam(basionymAuthor
);
456 testNoMoreElements();
458 childName
= "CombinationAuthorship";
460 Element elCombinationAuthorship
= XmlHelp
.getSingleChildElement(success
, elCanonicalAuthorship
, childName
, ns
, obligatory
);
461 INomenclaturalAuthor combinationAuthor
= makeNameCitation(elCombinationAuthorship
, authorMap
,success
);
462 if (combinationAuthor
!= null){
463 nonViralName
.setCombinationAuthorTeam(combinationAuthor
);
465 testNoMoreElements();
467 if (elAuthorship
!= null && (elBasionymAuthorship
!= null || elCombinationAuthorship
!= null) ){
468 logger
.warn("Authorship and (BasionymAuthorship or CombinationAuthorship) must not exist at the same time in CanonicalAuthorship");
469 success
.setValue(false);
476 private void makePublishedIn(TaxonNameBase name
, Element elPublishedIn
, MapWrapper
<Reference
> referenceMap
, ResultWrapper
<Boolean
> success
){
477 if (elPublishedIn
!= null && name
!= null){
478 Class
<?
extends Reference
> clazz
= Reference
.class;
479 Reference ref
= makeReferenceType(elPublishedIn
, clazz
, referenceMap
, success
);
480 if (ref
instanceof INomenclaturalReference
){
481 name
.setNomenclaturalReference(ref
);
483 logger
.warn("Reference is not of type INomenclaturalReference and could not be added to the name " + name
.getTitleCache());
485 }else if (name
== null){
486 logger
.warn("TaxonName must not be 'null'");
487 success
.setValue(false);
492 private void makeYear(TaxonNameBase name
, Element elYear
, ResultWrapper
<Boolean
> success
){
494 String year
= elYear
.getTextNormalize();
495 if (name
instanceof ZoologicalName
){
496 ((ZoologicalName
)name
).setPublicationYear(getIntegerYear(year
));
498 logger
.warn("Year can be set only for a zoological name");
503 private Integer
getIntegerYear(String year
){
505 Integer result
= Integer
.valueOf(year
);
507 } catch (NumberFormatException e
) {
508 logger
.warn("Year string could not be parsed. Set = 9999 instead");
514 private void makeMicroReference(TaxonNameBase name
, Element elMicroReference
, ResultWrapper
<Boolean
> success
){
515 if (elMicroReference
!= null){
516 String microReference
= elMicroReference
.getTextNormalize();
517 name
.setNomenclaturalMicroReference(microReference
);
522 private void makeTypification(TaxonNameBase name
, Element elTypifiacation
, ResultWrapper
<Boolean
> success
){
523 if (elTypifiacation
!= null){
524 //logger.warn("makeTypification not yet implemented");
525 //success.setValue(false);
530 private void makePublicationStatus(TaxonNameBase name
, Element elPublicationStatus
, ResultWrapper
<Boolean
> success
){
533 if (elPublicationStatus
!= null){
534 //logger.warn("makePublicationStatus not yet implemented");
535 //success.setValue(false);
539 private void makeProviderLink(TaxonNameBase name
, Element elProviderLink
, ResultWrapper
<Boolean
> success
){
540 if (elProviderLink
!= null){
541 //logger.warn("makeProviderLink not yet implemented");
542 //success.setValue(false);
547 private void makeProviderSpecificData(TaxonNameBase name
, Element elProviderSpecificData
, ResultWrapper
<Boolean
> success
){
548 if (elProviderSpecificData
!= null){
549 //logger.warn("makeProviderSpecificData not yet implemented");
550 //success.setValue(false);
556 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
558 protected boolean isIgnore(TcsXmlImportState state
){
559 return ! state
.getConfig().isDoTaxonNames();