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
.eflora
.centralAfrica
.ferns
;
12 import java
.sql
.ResultSet
;
13 import java
.sql
.SQLException
;
14 import java
.util
.Arrays
;
15 import java
.util
.HashMap
;
16 import java
.util
.HashSet
;
17 import java
.util
.List
;
20 import java
.util
.UUID
;
22 import org
.apache
.commons
.lang
.StringUtils
;
23 import org
.apache
.log4j
.Logger
;
24 import org
.springframework
.stereotype
.Component
;
26 import eu
.etaxonomy
.cdm
.api
.service
.IClassificationService
;
27 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
28 import eu
.etaxonomy
.cdm
.io
.common
.IOValidator
;
29 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.DbImportMapping
;
30 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.DbImportMethodMapper
;
31 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.DbImportTaxIncludedInMapper
;
32 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.IMappingImport
;
33 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
34 import eu
.etaxonomy
.cdm
.io
.eflora
.centralAfrica
.ferns
.validation
.CentralAfricaFernsTaxonImportValidator
;
35 import eu
.etaxonomy
.cdm
.model
.agent
.INomenclaturalAuthor
;
36 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
37 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
38 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
39 import eu
.etaxonomy
.cdm
.model
.description
.Distribution
;
40 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
41 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
42 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
43 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
44 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
45 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
46 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
47 import eu
.etaxonomy
.cdm
.model
.location
.TdwgArea
;
48 import eu
.etaxonomy
.cdm
.model
.location
.WaterbodyOrCountry
;
49 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
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
.taxon
.Classification
;
55 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
56 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
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
.model
.taxon
.TaxonNode
;
68 public class CentralAfricaFernsTaxonRelationImport
extends CentralAfricaFernsImportBase
<TaxonBase
> implements IMappingImport
<TaxonBase
, CentralAfricaFernsImportState
>{
69 private static final Logger logger
= Logger
.getLogger(CentralAfricaFernsTaxonRelationImport
.class);
71 private DbImportMapping mapping
;
74 private static final String pluralString
= "taxon relations";
75 private static final String dbTableName
= "[African pteridophytes]";
76 private static final Class cdmTargetClass
= TaxonBase
.class;
78 private Map
<String
, UUID
> nameCacheTaxonMap
= new HashMap
<String
, UUID
>();
79 private Map
<String
, UUID
> titleCacheTaxonMap
= new HashMap
<String
, UUID
>();
81 private CentralAfricaFernsImportState state
;
84 public CentralAfricaFernsTaxonRelationImport(){
85 super(pluralString
, dbTableName
, cdmTargetClass
);
91 * @see eu.etaxonomy.cdm.io.erms.ErmsImportBase#getIdQuery()
94 protected String
getIdQuery() {
95 String strQuery
= " SELECT [Taxon number] FROM " + dbTableName
;;
101 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getMapping()
104 protected DbImportMapping
getMapping() {
105 if (mapping
== null){
106 mapping
= new DbImportMapping();
108 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "createObject", ResultSet
.class, CentralAfricaFernsImportState
.class));
109 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapCommonName", ResultSet
.class, CentralAfricaFernsImportState
.class));
110 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapDistribution", ResultSet
.class, CentralAfricaFernsImportState
.class ));
111 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapEcology", ResultSet
.class, CentralAfricaFernsImportState
.class));
118 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getRecordQuery(eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportConfigurator)
121 protected String
getRecordQuery(CentralAfricaFernsImportConfigurator config
) {
122 String strSelect
= " SELECT * ";
123 String strFrom
= " FROM [African pteridophytes] as ap";
124 String strWhere
= " WHERE ( ap.[taxon number] IN (" + ID_LIST_TOKEN
+ ") )";
125 String strOrderBy
= " ORDER BY [Taxon number]";
126 String strRecordQuery
= strSelect
+ strFrom
+ strWhere
+ strOrderBy
;
127 return strRecordQuery
;
132 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#doInvoke(eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportState)
135 protected void doInvoke(CentralAfricaFernsImportState state
) {
138 super.doInvoke(state
);
144 * Fills the nameCache and the titleCache maps. The maps are used to find existing taxa
145 * by titleCache or nameCache matching.
146 * Matching may be implemented more sophisticated in future versions.
148 private void fillTaxonMap() {
149 List
<String
> propPath
= Arrays
.asList(new String
[]{"name"});
151 List
<Taxon
> taxonList
= (List
)getTaxonService().list(Taxon
.class, null, null, null, propPath
);
152 for (Taxon taxon
: taxonList
){
153 NonViralName nvn
= CdmBase
.deproxy(taxon
.getName(), NonViralName
.class);
154 UUID uuid
= taxon
.getUuid();
155 String nameCache
= nvn
.getNameCache();
156 String titleCache
= nvn
.getTitleCache();
157 nameCacheTaxonMap
.put(nameCache
, uuid
);
158 titleCacheTaxonMap
.put(titleCache
, uuid
);
163 * @see eu.etaxonomy.cdm.io.common.IPartitionedIO#getRelatedObjectsForPartition(java.sql.ResultSet)
165 public Map
<Object
, Map
<String
, ?
extends CdmBase
>> getRelatedObjectsForPartition(ResultSet rs
) {
169 Map
<Object
, Map
<String
, ?
extends CdmBase
>> result
= new HashMap
<Object
, Map
<String
, ?
extends CdmBase
>>();
172 Set
<String
> taxonIdSet
= new HashSet
<String
>();
173 // Set<String> referenceIdSet = new HashSet<String>();
175 handleForeignKey(rs
, taxonIdSet
, "Current");
176 handleForeignKey(rs
, taxonIdSet
, "Taxon number");
177 // handleForeignKey(rs, referenceIdSet, "PTRefFk");
181 nameSpace
= TAXON_NAMESPACE
;
182 cdmClass
= TaxonBase
.class;
183 Map
<String
, TaxonBase
> taxonMap
= (Map
<String
, TaxonBase
>)getCommonService().getSourcedObjectsByIdInSource(cdmClass
, taxonIdSet
, nameSpace
);
184 result
.put(nameSpace
, taxonMap
);
188 this.sourceReference
= getFernsSourceReference(state
);
189 // nameSpace = "Reference";
190 // cdmClass = Reference.class;
191 // Map<String, Person> referenceMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(Person.class, teamIdSet, nameSpace);
192 // result.put(Reference.class, referenceMap);
194 } catch (SQLException e
) {
195 throw new RuntimeException(e
);
202 * @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet, eu.etaxonomy.cdm.io.common.ImportStateBase)
205 public TaxonBase
createObject(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
206 TaxonBase result
= null;
208 String status
= rs
.getString("Current/Synonym");
209 String taxonNumber
= rs
.getString("Taxon number");
210 state
.setTaxonNumber(taxonNumber
);
211 if ("s".equalsIgnoreCase(status
)){
213 result
= handleSynonym(rs
, state
);
216 result
= handleTaxon(rs
, state
);
220 } catch (Exception e
) {
229 * Class to store all epithets of the database record. Maybe extended with business logic.
231 private class Epithets
{
232 private String orderName
;
233 private String subOrderName
;
234 private String familyName
;
235 private String subFamilyName
;
236 private String tribusName
;
237 private String subTribusName
;
238 private String sectionName
;
239 private String subsectionName
;
240 private String genusName
;
241 private String subGenusName
;
242 private String seriesName
;
243 private String specificEpithet
;
244 private String subspeciesName
;
245 private String varietyName
;
246 private String subVariety
;
247 private String formaName
;
248 private String subFormaName
;
253 * Handles records with status synonym. A synonym relationship to the accepted taxon
258 * @throws SQLException
260 private Synonym
handleSynonym(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
261 String accTaxonId
= rs
.getString("Current");
262 String nomRemarksString
= rs
.getString("Current/Synonym");
264 String synonymId
= state
.getTaxonNumber();
265 Synonym synonym
= (Synonym
)state
.getRelatedObject(TAXON_NAMESPACE
, synonymId
);
266 if (synonym
== null){
267 logger
.warn ("Synonym ("+synonymId
+")not found.");
270 TaxonBase taxonBase
= CdmBase
.deproxy(state
.getRelatedObject(TAXON_NAMESPACE
, accTaxonId
), TaxonBase
.class);
272 if (taxonBase
!= null){
273 if (taxonBase
.isInstanceOf(Taxon
.class)){
274 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
275 SynonymRelationship rel
= taxon
.addSynonym(synonym
, SynonymRelationshipType
.SYNONYM_OF());
276 if ("p.p.".equalsIgnoreCase(nomRemarksString
)){
277 rel
.setProParte(true);
280 logger
.warn("Accepted taxon (" + accTaxonId
+ ") for synonym (" + synonymId
+") is not of type 'Current'");
283 logger
.warn("Taxon (" + accTaxonId
+ ") not found for synonym (" + synonymId
+")");
291 * Handles all records with status 'current'. Creates parent-child relationships to the
292 * higher taxa. Uses a complex algorithm to reuse existing higher taxa.
296 * @throws SQLException
298 private Taxon
handleTaxon(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
299 String taxonNumber
= rs
.getString("Taxon number");
300 Taxon child
= (Taxon
)state
.getRelatedObject(TAXON_NAMESPACE
, taxonNumber
);
302 logger
.warn("Taxon does not exist: " + taxonNumber
);
305 Epithets epithets
= new Epithets();
306 epithets
.orderName
= rs
.getString("Order name");
307 epithets
.subOrderName
= rs
.getString("Suborder name");
308 epithets
.familyName
= rs
.getString("Family name");
309 epithets
.subFamilyName
= rs
.getString("Subfamily name");
310 epithets
.tribusName
= rs
.getString("Tribus name");
311 epithets
.subTribusName
= rs
.getString("Subtribus name");
312 epithets
.sectionName
= rs
.getString("Section name");
313 epithets
.subsectionName
= rs
.getString("Subsection name");
314 epithets
.genusName
= rs
.getString("Genus name");
315 epithets
.subGenusName
= rs
.getString("Subgenus name");
316 epithets
.seriesName
= rs
.getString("Series name");
317 epithets
.specificEpithet
= rs
.getString("Specific epihet");
318 epithets
.subspeciesName
= rs
.getString("Subspecies name");
319 epithets
.varietyName
= rs
.getString("Variety name");
320 epithets
.subVariety
= rs
.getString("Subvariery");
321 epithets
.formaName
= rs
.getString("Forma name");
322 epithets
.subFormaName
= rs
.getString("Subforma");
324 makeNextHigherTaxon(state
, rs
, child
, epithets
);
330 * Adds recursively this taxon to the next higher taxon. If the taxon exists already
331 * the relationship is not added again.<BR>
332 * If the author is missing in the old taxon but not in the new taxon the
333 * old taxon will get the new taxons author.(NOT VALID ANY MORE)<BR>
334 * If authors differ a new taxon is created.<BR>
335 * If a higher taxon exists the method is called recursively on this taxon.
336 * @throws SQLException
338 private void makeNextHigherTaxon(CentralAfricaFernsImportState state
, ResultSet rs
, Taxon child
, Epithets epithets
) throws SQLException
{
340 Taxon constructedHigherTaxon
= constructNextHigherTaxon(state
, rs
, child
, epithets
);
341 Reference
<?
> citation
= null;
342 String microcitation
= null;
344 if (constructedHigherTaxon
!= null){
345 handleHigherTaxonMustExist(state
, rs
, child
, epithets
, constructedHigherTaxon
, citation
, microcitation
);
347 //add taxon to tree if not yet added
348 if (child
.getTaxonNodes().size() == 0){
349 makeTaxonomicallyIncluded(state
, null, child
, null, citation
, microcitation
);
357 * Handles the case when the database record has data for a taxon of a higher rank
358 * than the <code>child</code> taxon's rank.
365 * @param microcitation
366 * @throws SQLException
368 private void handleHigherTaxonMustExist(CentralAfricaFernsImportState state
, ResultSet rs
, Taxon child
, Epithets epithets
, Taxon constructedHigherTaxon
, Reference
<?
> citation
, String microCitation
) throws SQLException
{
369 Taxon parentTaxon
= getParent(child
);
370 if (parentTaxon
== null){
371 //if no parent taxon exists
372 Taxon existingTaxon
= findExistingNonParentTaxon(state
, constructedHigherTaxon
);
373 if (existingTaxon
!= null){
374 //a taxon with same title cache or same name cache exists
375 parentTaxon
= mergeExistingAndConstructedTaxon(state
, existingTaxon
, constructedHigherTaxon
);
377 parentTaxon
= constructedHigherTaxon
;
379 makeTaxonomicallyIncluded(state
, null, child
, parentTaxon
, citation
, microCitation
);
381 //parent taxon exists
382 if (namesMatch(parentTaxon
, constructedHigherTaxon
)){
384 //TODO what if the higher taxonomy does not match
385 parentTaxon
= mergeExistingAndConstructedTaxon(state
, parentTaxon
, constructedHigherTaxon
);
386 }else if (compareRanks(parentTaxon
, constructedHigherTaxon
) != 0){
388 parentTaxon
= handleUnequalRanks(parentTaxon
, constructedHigherTaxon
);
389 }else if (! nameCachesMatch(parentTaxon
, constructedHigherTaxon
)){
390 //nameCache not equal
391 parentTaxon
= handleUnequalNameCaches(parentTaxon
, constructedHigherTaxon
);
392 }else if (! authorsMatch(parentTaxon
, constructedHigherTaxon
)){
393 //nameCache not equal
394 parentTaxon
= handleUnequalAuthors(parentTaxon
, constructedHigherTaxon
);
397 //save the parent taxon, if it is new
398 if (parentTaxon
== constructedHigherTaxon
){
399 saveConstructedTaxon(state
, constructedHigherTaxon
);
401 makeNextHigherTaxon(state
, rs
, parentTaxon
, epithets
);
406 * Merges author information of the constructed taxon into the existing taxon.
407 * Returns the existing taxon.
410 * @param constructedHigherTaxon
412 private Taxon
mergeExistingAndConstructedTaxon(CentralAfricaFernsImportState state
, Taxon existingTaxon
, Taxon constructedTaxon
) {
413 NonViralName constructedName
= CdmBase
.deproxy(constructedTaxon
.getName(), NonViralName
.class);
414 NonViralName existingName
= CdmBase
.deproxy(existingTaxon
.getName(), NonViralName
.class);
415 if (constructedName
.hasAuthors()){
416 if (! existingName
.hasAuthors()){
417 logger
.warn(state
.getTaxonNumber() + " - Constrcucted name ("+constructedName
.getTitleCache()+") has authors but existing name ("+existingName
.getTitleCache()+") has no authors");
418 }else if (! authorsMatch(constructedName
, existingName
)){
419 logger
.warn(state
.getTaxonNumber() + " - Constrcucted name ("+constructedName
.getTitleCache()+") and existing name ("+existingName
.getTitleCache()+") have different authors");
421 //authors match and are not null
425 return existingTaxon
;
430 * Strategy for the decision if an existing parent or a constructed higher taxon should
431 * be taken as parent in case that the authors of the name differ somehow.
432 * Current strategy: use existing parent if constructed higher taxon has no authors
433 * at all. Use constructed taxon otherwise.
434 * @param existingParentTaxon
435 * @param constructedHigherTaxon
438 private Taxon
handleUnequalAuthors(Taxon existingParentTaxon
, Taxon constructedHigherTaxon
) {
440 BotanicalName existingName
= CdmBase
.deproxy(existingParentTaxon
.getName(), BotanicalName
.class);
441 BotanicalName constructedName
= (BotanicalName
)constructedHigherTaxon
.getName();
442 //current strategy: if constructedName has no authors (and parentName has
443 if (! constructedName
.hasAuthors()){
444 result
= existingParentTaxon
;
445 }else if (! existingName
.hasAuthors()){
446 result
= constructedHigherTaxon
;
448 result
= constructedHigherTaxon
;
454 * Strategy for the decision if an existing parent or a constructed higher taxon
455 * should be taken as parent in case that the name caches differ somehow.
456 * Current strategy: Not implemented. Always use constructed higher taxon.
457 * @param existingParentTaxon
458 * @param constructedHigherTaxon
461 private Taxon
handleUnequalNameCaches(Taxon parentTaxon
, Taxon constructedHigherTaxon
) {
462 BotanicalName parentName
= CdmBase
.deproxy(parentTaxon
.getName(), BotanicalName
.class);
463 BotanicalName constructedName
= (BotanicalName
)constructedHigherTaxon
.getName();
464 logger
.warn("handleUnequalNameCaches not yet implemented");
465 return constructedHigherTaxon
;
470 * Handles the case that the existing parent taxon and the constructed parent taxon
471 * have a diffent rank. Returns the constructedHigherTaxon if no common grand parent exists.
473 * @param constructedHigherTaxon
476 private Taxon
handleUnequalRanks(Taxon parentTaxon
, Taxon constructedHigherTaxon
) {
477 BotanicalName parentName
= CdmBase
.deproxy(parentTaxon
.getName(), BotanicalName
.class);
478 BotanicalName constructedName
= (BotanicalName
)constructedHigherTaxon
.getName();
479 int compare
= compareRanks(parentName
, constructedName
);
480 Taxon lowerTaxon
= parentTaxon
;
481 Taxon grandParentTaxon
= constructedHigherTaxon
;
483 lowerTaxon
= constructedHigherTaxon
;
484 grandParentTaxon
= parentTaxon
;
486 Taxon commonGrandParent
= checkIsGrandParent(lowerTaxon
, grandParentTaxon
);
487 if (commonGrandParent
!= null){
488 if (lowerTaxon
== constructedHigherTaxon
){
490 logger
.warn("Merge in between taxon not yet implemented");
493 return constructedHigherTaxon
;
499 * Tries to find a taxon which matches the constructed taxon but is not a parent
500 * taxon of the constructed taxon's child (condition will not be checked).
501 * Returns null if no such taxon exists.
502 * @param constructedHigherTaxon
506 private Taxon
findExistingNonParentTaxon(CentralAfricaFernsImportState state
, Taxon constructedHigherTaxon
) {
507 BotanicalName constructedName
= CdmBase
.deproxy(constructedHigherTaxon
.getName(), BotanicalName
.class);
508 String titleCache
= constructedName
.getTitleCache();
509 String nameCache
= constructedName
.getNameCache();
510 UUID existingUuid
= titleCacheTaxonMap
.get(titleCache
);
511 if (existingUuid
== null){
512 existingUuid
= nameCacheTaxonMap
.get(nameCache
);
514 Taxon relatedTaxon
= null;
515 if (existingUuid
!= null){
516 relatedTaxon
= state
.getRelatedObject(HIGHER_TAXON_NAMESPACE
, nameCache
, Taxon
.class);
517 if (relatedTaxon
== null){
518 //TODO find for partition
519 relatedTaxon
= (Taxon
)getTaxonService().find(existingUuid
);
520 if (relatedTaxon
== null){
521 logger
.info(state
.getTaxonNumber() + " - Could not find existing name ("+nameCache
+") in related objects map");
523 state
.addRelatedObject(HIGHER_TAXON_NAMESPACE
, nameCache
, relatedTaxon
);
531 * Checks if a taxon is a grand parent of another taxon
536 private Taxon
checkIsGrandParent(Taxon childTaxon
, Taxon grandParentTaxon
) {
537 BotanicalName lowerName
= CdmBase
.deproxy(childTaxon
.getName(), BotanicalName
.class);
538 BotanicalName higherName
= CdmBase
.deproxy(grandParentTaxon
.getName(), BotanicalName
.class);
540 //TODO was wenn lowerTaxon constructed ist
541 logger
.warn("checkIsGrandParent not yet fully implemented");
542 Taxon nextParent
= getParent(childTaxon
);
543 if (namesMatch(nextParent
, grandParentTaxon
)){
544 //TODO which one to return? Merging ?
545 logger
.warn("checkIsGrandParent(matching) not yet fully implemented");
546 return grandParentTaxon
;
548 if (compareRanks(lowerName
, higherName
) >= 0){
551 return checkIsGrandParent(childTaxon
, grandParentTaxon
);
558 * Checks if the name caches match.
563 private boolean nameCachesMatch(BotanicalName name1
, BotanicalName name2
) {
564 return CdmUtils
.nullSafeEqual(name1
.getNameCache(), name2
.getNameCache());
568 * Checks if the name caches of the related names match.
573 private boolean nameCachesMatch(Taxon taxon1
, Taxon taxon2
) {
574 BotanicalName name1
= CdmBase
.deproxy(taxon1
.getName(), BotanicalName
.class);
575 BotanicalName name2
= CdmBase
.deproxy(taxon2
.getName(), BotanicalName
.class);
576 return nameCachesMatch(name1
, name2
);
581 * Checks if all authors match
586 private boolean authorsMatch(NonViralName
<?
> name1
, NonViralName
<?
> name2
) {
587 String combinationAuthor1
= name1
.computeCombinationAuthorNomenclaturalTitle();
588 String combinationAuthor2
= name2
.computeCombinationAuthorNomenclaturalTitle();
589 String basionymAuthor1
= name1
.computeBasionymAuthorNomenclaturalTitle();
590 String basionymAuthor2
= name2
.computeBasionymAuthorNomenclaturalTitle();
591 String exCombinationAuthor1
= name1
.computeExCombinationAuthorNomenclaturalTitle();
592 String exCombinationAuthor2
= name2
.computeExCombinationAuthorNomenclaturalTitle();
593 String exBasionymAuthor1
= name1
.computeExBasionymAuthorNomenclaturalTitle();
594 String exBasionymAuthor2
= name2
.computeExBasionymAuthorNomenclaturalTitle();
596 CdmUtils
.nullSafeEqual(combinationAuthor1
, combinationAuthor2
) &&
597 CdmUtils
.nullSafeEqual(basionymAuthor1
, basionymAuthor2
) &&
598 CdmUtils
.nullSafeEqual(exCombinationAuthor1
, exCombinationAuthor2
) &&
599 CdmUtils
.nullSafeEqual(exBasionymAuthor1
, exBasionymAuthor2
);
604 * Checks if all authors of the related names match.
609 private boolean authorsMatch(Taxon taxon1
, Taxon taxon2
) {
610 BotanicalName name1
= CdmBase
.deproxy(taxon1
.getName(), BotanicalName
.class);
611 BotanicalName name2
= CdmBase
.deproxy(taxon2
.getName(), BotanicalName
.class);
612 return authorsMatch(name1
, name2
);
616 * Compares ranks of 2 names.
618 * @param constructedName
621 private int compareRanks(BotanicalName name1
, BotanicalName name2
) {
622 return name1
.getRank().compareTo(name2
.getRank());
626 * Compares the ranks of the according names.
631 private int compareRanks(Taxon taxon1
, Taxon taxon2
) {
632 BotanicalName name1
= CdmBase
.deproxy(taxon1
.getName(), BotanicalName
.class);
633 BotanicalName name2
= CdmBase
.deproxy(taxon2
.getName(), BotanicalName
.class);
634 return compareRanks(name1
, name2
);
640 * Checks if 2 names match.
641 * Current strategy: true, if ranks are equal, nameCaches match and authors match
646 private boolean namesMatch(BotanicalName name1
, BotanicalName name2
) {
647 return compareRanks(name1
, name2
)==0 && nameCachesMatch(name1
, name2
) && authorsMatch(name1
, name2
);
651 * Checks if the according names match.
652 * @see #namesMatch(BotanicalName, BotanicalName)
657 private boolean namesMatch(Taxon taxon1
, Taxon taxon2
) {
658 BotanicalName name1
= CdmBase
.deproxy(taxon1
.getName(), BotanicalName
.class);
659 BotanicalName name2
= CdmBase
.deproxy(taxon2
.getName(), BotanicalName
.class);
660 return namesMatch(name1
, name2
);
665 * Returns the only parent of the taxon. If not parent exists <code>null</code> is
667 * TODO move to taxon class (with classification)
670 * @throws IllegalStateException if taxon belongs to multiple states
672 private Taxon
getParent(Taxon child
) {
673 int countNodes
= child
.getTaxonNodes().size();
676 }else if (countNodes
> 1){
677 throw new IllegalStateException("Multiple nodes exist for child taxon. This is an invalid state for this import.");
679 TaxonNode childNode
= child
.getTaxonNodes().iterator().next();
680 TaxonNode parentNode
= childNode
.getParent();
681 if (parentNode
!= null){
682 return parentNode
.getTaxon();
691 * Persists and saves the newly created taxon to the CDM store and to the look-up
694 * @param constructedHigherTaxon
697 private Taxon
saveConstructedTaxon(CentralAfricaFernsImportState state
, Taxon constructedHigherTaxon
) {
698 BotanicalName constructedName
= CdmBase
.deproxy(constructedHigherTaxon
.getName(), BotanicalName
.class);
699 String nameCache
= constructedName
.getNameCache();
700 String titleCache
= constructedName
.getTitleCache();
701 nameCacheTaxonMap
.put(nameCache
, constructedHigherTaxon
.getUuid());
702 titleCacheTaxonMap
.put(titleCache
, constructedHigherTaxon
.getUuid());
703 state
.addRelatedObject(HIGHER_TAXON_NAMESPACE
, nameCache
, constructedHigherTaxon
);
706 // Reference citation = state.getConfig().getSourceReference(); //throws nonUniqueObject exception
707 Reference citation
= null;
708 String id
= state
.getTaxonNumber() + "-" + constructedName
.getRank().getTitleCache();
709 addOriginalSource(constructedName
, id
, NAME_NAMESPACE
, citation
);
710 addOriginalSource(constructedHigherTaxon
, id
, TAXON_NAMESPACE
, citation
);
711 getTaxonService().save(constructedHigherTaxon
);
713 return constructedHigherTaxon
;
719 * Adds the parent child relationship. Creates and saves the classification if needed.
720 * Adds parent and child to the classification.
726 * @param microCitation
729 private boolean makeTaxonomicallyIncluded(CentralAfricaFernsImportState state
, Integer treeRefFk
, Taxon child
, Taxon parent
, Reference citation
, String microCitation
){
732 if (treeRefFk
== null){
733 treeKey
= "1"; // there is only one tree and it gets the map key '1'
734 treeUuid
= state
.getConfig().getClassificationUuid();
736 treeKey
=String
.valueOf(treeRefFk
);
737 treeUuid
= state
.getTreeUuidByTreeKey(treeKey
);
739 Classification tree
= (Classification
)state
.getRelatedObject(DbImportTaxIncludedInMapper
.TAXONOMIC_TREE_NAMESPACE
, treeKey
);
741 IClassificationService service
= state
.getCurrentIO().getClassificationService();
742 tree
= service
.find(treeUuid
);
744 String treeName
= state
.getConfig().getClassificationName();
745 tree
= Classification
.NewInstance(treeName
);
746 tree
.setUuid(treeUuid
);
747 //FIXME tree reference
748 tree
.setReference(citation
);
751 state
.addRelatedObject(DbImportTaxIncludedInMapper
.TAXONOMIC_TREE_NAMESPACE
, treeKey
, tree
);
756 childNode
= tree
.addParentChild(parent
, child
, citation
, microCitation
);
758 childNode
= tree
.addChildTaxon(child
, citation
, microCitation
, null);
760 return (childNode
!= null);
765 * Reasons if a higher taxon should exist. If it should exist it returns it as a new taxon.
766 * Returns null otherwise.
768 * @throws SQLException
770 private Taxon
constructNextHigherTaxon(CentralAfricaFernsImportState state
, ResultSet rs
, Taxon childTaxon
, Epithets epithets
) throws SQLException
{
773 BotanicalName childName
= CdmBase
.deproxy(childTaxon
.getName(), BotanicalName
.class);
774 Rank childRank
= childName
.getRank();
775 BotanicalName higherName
;
776 higherName
= handleInfraSpecific(childRank
, epithets
);
777 if (higherName
.getRank() == null){
778 handleSpecies(childRank
, higherName
, epithets
);
780 if (higherName
.getRank() == null){
781 handleInfraGeneric(childRank
, higherName
, epithets
);
783 if (higherName
.getRank() == null){
784 handleUninomial(childRank
, higherName
, epithets
);
787 if (higherName
.getRank() != null){
788 result
= Taxon
.NewInstance(higherName
, childTaxon
.getSec());
790 setAuthor(higherName
, rs
, state
.getTaxonNumber(), true);
791 // UUID uuid = higherName.getUuid();
792 // String name = higherName.getNameCache();
793 // taxonMap.put(name, uuid);
794 // state.addRelatedObject(HIGHER_TAXON_NAMESPACE, higherName.getNameCache(), result);
799 private BotanicalName
handleInfraSpecific(Rank lowerTaxonRank
, Epithets epithets
) {
801 BotanicalName taxonName
= BotanicalName
.NewInstance(null);
804 if (StringUtils
.isNotBlank(epithets
.subFormaName
) && lowerTaxonRank
.isLower(Rank
.SUBFORM())){
805 taxonName
.setInfraSpecificEpithet(epithets
.subFormaName
);
806 newRank
= Rank
.SUBFORM();
807 }else if (StringUtils
.isNotBlank(epithets
.formaName
) && lowerTaxonRank
.isLower(Rank
.FORM())){
808 taxonName
.setInfraSpecificEpithet(epithets
.formaName
);
809 newRank
= Rank
.FORM();
810 }else if (StringUtils
.isNotBlank(epithets
.subVariety
) && lowerTaxonRank
.isLower(Rank
.SUBVARIETY())){
811 taxonName
.setInfraSpecificEpithet(epithets
.subVariety
);
812 newRank
= Rank
.SUBVARIETY();
813 }else if (StringUtils
.isNotBlank(epithets
.varietyName
) && lowerTaxonRank
.isLower(Rank
.VARIETY())){
814 taxonName
.setInfraSpecificEpithet(epithets
.varietyName
);
815 newRank
= Rank
.VARIETY();
816 }else if (StringUtils
.isNotBlank(epithets
.subspeciesName
) && lowerTaxonRank
.isLower(Rank
.SUBSPECIES())){
817 taxonName
.setInfraSpecificEpithet(epithets
.subspeciesName
);
818 newRank
= Rank
.SUBSPECIES();
821 if (newRank
!= null){
822 taxonName
.setSpecificEpithet(epithets
.specificEpithet
);
823 taxonName
.setGenusOrUninomial(epithets
.genusName
);
824 taxonName
.setRank(newRank
);
830 private BotanicalName
handleSpecies(Rank lowerTaxonRank
, BotanicalName taxonName
, Epithets epithets
) {
833 if (StringUtils
.isNotBlank(epithets
.specificEpithet
) && lowerTaxonRank
.isLower(Rank
.SPECIES())){
834 taxonName
.setSpecificEpithet(epithets
.specificEpithet
);
835 newRank
= Rank
.SPECIES();
837 if (newRank
!= null){
838 taxonName
.setGenusOrUninomial(epithets
.genusName
);
839 taxonName
.setRank(newRank
);
844 private BotanicalName
handleInfraGeneric(Rank lowerTaxonRank
, BotanicalName taxonName
, Epithets epithets
) {
847 if (StringUtils
.isNotBlank(epithets
.seriesName
) && lowerTaxonRank
.isLower(Rank
.SERIES())){
848 taxonName
.setInfraGenericEpithet(epithets
.seriesName
);
849 newRank
= Rank
.SERIES();
850 }else if (StringUtils
.isNotBlank(epithets
.subsectionName
) && lowerTaxonRank
.isLower(Rank
.SUBSECTION_BOTANY())){
851 taxonName
.setInfraGenericEpithet(epithets
.subsectionName
);
852 newRank
= Rank
.SUBSECTION_BOTANY();
853 }else if (StringUtils
.isNotBlank(epithets
.sectionName
) && lowerTaxonRank
.isLower(Rank
.SECTION_BOTANY())){
854 taxonName
.setInfraGenericEpithet(epithets
.sectionName
);
855 newRank
= Rank
.SECTION_BOTANY();
856 }else if (StringUtils
.isNotBlank(epithets
.subGenusName
) && lowerTaxonRank
.isLower(Rank
.SUBGENUS())){
857 taxonName
.setInfraGenericEpithet(epithets
.subGenusName
);
858 newRank
= Rank
.SUBGENUS();
860 if (newRank
!= null){
861 taxonName
.setGenusOrUninomial(epithets
.genusName
);
862 taxonName
.setRank(newRank
);
869 private BotanicalName
handleUninomial(Rank lowerTaxonRank
, BotanicalName taxonName
, Epithets epithets
) {
872 if (StringUtils
.isNotBlank(epithets
.genusName
) && lowerTaxonRank
.isLower(Rank
.GENUS())){
873 taxonName
.setGenusOrUninomial(epithets
.genusName
);
874 newRank
= Rank
.GENUS();
875 }else if (StringUtils
.isNotBlank(epithets
.subTribusName
) && lowerTaxonRank
.isLower(Rank
.SUBTRIBE())){
876 taxonName
.setGenusOrUninomial(epithets
.subTribusName
);
877 newRank
= Rank
.SUBTRIBE();
878 }else if (StringUtils
.isNotBlank(epithets
.tribusName
) && lowerTaxonRank
.isLower(Rank
.TRIBE())){
879 taxonName
.setGenusOrUninomial(epithets
.tribusName
);
880 newRank
= Rank
.TRIBE();
881 }else if (StringUtils
.isNotBlank(epithets
.subFamilyName
) && lowerTaxonRank
.isLower(Rank
.SUBFAMILY())){
882 taxonName
.setGenusOrUninomial(epithets
.subFamilyName
);
883 newRank
= Rank
.SUBFAMILY();
884 }else if (StringUtils
.isNotBlank(epithets
.familyName
) && lowerTaxonRank
.isLower(Rank
.FAMILY())){
885 taxonName
.setGenusOrUninomial(epithets
.familyName
);
886 newRank
= Rank
.FAMILY();
887 }else if (StringUtils
.isNotBlank(epithets
.subOrderName
) && lowerTaxonRank
.isLower(Rank
.SUBORDER())){
888 taxonName
.setGenusOrUninomial(epithets
.subOrderName
);
889 newRank
= Rank
.SUBORDER();
890 }else if (StringUtils
.isNotBlank(epithets
.orderName
) && lowerTaxonRank
.isLower(Rank
.ORDER())){
891 taxonName
.setGenusOrUninomial(epithets
.orderName
);
892 newRank
= Rank
.ORDER();
894 taxonName
.setRank(newRank
);
900 * for internal use only, used by MethodMapper
902 private TaxonBase
mapCommonName(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
903 String taxonNumber
= state
.getTaxonNumber();
904 String commonNames
= rs
.getString("Common names");
905 TaxonBase
<?
> taxonBase
= state
.getRelatedObject(state
.CURRENT_OBJECT_NAMESPACE
, state
.CURRENT_OBJECT_ID
, TaxonBase
.class);
906 if (StringUtils
.isNotBlank(commonNames
)){
907 Taxon taxon
= getAcceptedTaxon(taxonBase
);
908 if ( taxon
!= null ){
909 TaxonDescription description
= getTaxonDescription(taxon
, false, true);
910 String
[] split
= commonNames
.split(",");
911 for (String commonNameString
: split
){
912 CommonTaxonName commonName
= CommonTaxonName
.NewInstance(commonNameString
.trim(), Language
.ENGLISH());
913 description
.addElement(commonName
);
916 logger
.warn(taxonNumber
+ " - Accepted taxon for synonym can't be defined for common name. Synonym " + taxonBase
.getName().getTitleCache());
924 * for internal use only, used by MethodMapper
926 private TaxonBase
mapDistribution(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
928 String taxonNumber
= state
.getTaxonNumber();
929 // logger.info(taxonNumber);
930 TaxonBase
<?
> taxonBase
= state
.getRelatedObject(state
.CURRENT_OBJECT_NAMESPACE
, state
.CURRENT_OBJECT_ID
, TaxonBase
.class);
931 String countriesString
= rs
.getString("Distribution - Country");
932 String province
= rs
.getString("Distribution - Province");
933 String distributionDetailed
= rs
.getString("Distribution - detailed");
934 if (taxonBase
!= null){
935 TaxonNameBase nameUsedInSource
= taxonBase
.getName();
936 Taxon taxon
= getAcceptedTaxon(taxonBase
);
939 if (StringUtils
.isNotBlank(countriesString
) ){
940 makeCountries(state
, taxonNumber
, taxon
, nameUsedInSource
, countriesString
, province
, distributionDetailed
);
942 makeProvince(taxon
, province
);
943 makeDistributionDetailed(taxon
, distributionDetailed
);
945 logger
.warn(taxonNumber
+ " - Accepted taxon for synonym can't be defined for distribution. Synonym " + taxonBase
.getName().getTitleCache());
948 logger
.warn(" - " + taxonNumber
+ ": TaxonBase was null");
951 } catch (Exception e
) {
959 * for internal use only, used by MethodMapper
962 private TaxonBase
mapEcology(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
963 String taxonNumber
= state
.getTaxonNumber();
964 String ecologyString
= rs
.getString("Ecology");
965 TaxonBase
<?
> taxonBase
= state
.getRelatedObject(state
.CURRENT_OBJECT_NAMESPACE
, state
.CURRENT_OBJECT_ID
, TaxonBase
.class);
966 if (StringUtils
.isNotBlank(ecologyString
)){
967 Taxon taxon
= getAcceptedTaxon(taxonBase
);
970 TaxonDescription description
= getTaxonDescription(taxon
, false, true);
971 TextData ecology
= TextData
.NewInstance(Feature
.ECOLOGY());
972 ecology
.putText(Language
.ENGLISH(), ecologyString
.trim());
973 description
.addElement(ecology
);
975 logger
.warn(taxonNumber
+ " - Accepted taxon for synonym can't be defined for ecology. Synonym " + taxonBase
.getName().getTitleCache());
984 private void makeDistributionDetailed(Taxon taxon
, String distributionDetailed
) {
985 if (StringUtils
.isNotBlank(distributionDetailed
)){
986 TaxonDescription description
= getTaxonDescription(taxon
, false, true);
987 TextData distribution
= TextData
.NewInstance(Feature
.DISTRIBUTION());
988 description
.addElement(distribution
);
989 distribution
.putText(Language
.ENGLISH(), distributionDetailed
);
994 private void makeProvince(Taxon taxon
, String province
) {
995 if (StringUtils
.isNotBlank(province
)){
996 TaxonDescription description
= getTaxonDescription(taxon
, false, true);
997 TextData distribution
= TextData
.NewInstance(Feature
.DISTRIBUTION());
998 description
.addElement(distribution
);
999 distribution
.putText(Language
.ENGLISH(), province
);
1006 * @param taxonNumber
1008 * @param countriesString
1010 private void makeCountries(CentralAfricaFernsImportState state
, String taxonNumber
, Taxon taxon
, TaxonNameBase nameUsedInSource
, String countriesString
, String province
, String distributionDetailed
) {
1011 countriesString
= countriesString
.replaceAll("\\*", "");
1012 countriesString
= countriesString
.replace(" ", " ");
1013 countriesString
= countriesString
.replace(", endemic", " - endemic");
1014 countriesString
= countriesString
.replace("(endemic)", " - endemic");
1015 countriesString
= countriesString
.replace("(introduced)", " - introduced");
1016 countriesString
= countriesString
.replace("(naturalised)", " - naturalised");
1017 countriesString
= countriesString
.replace("Madagascar-", "Madagascar -");
1018 countriesString
= countriesString
.replace("Mahé", "Mahe");
1020 String
[] split
= countriesString
.split("[,;]");
1021 String remainingString
= null;
1022 for (String countryString
: split
){
1023 countryString
= CdmUtils
.concat(", ", remainingString
, countryString
);
1024 if (countryString
.matches(".*\\(.*") && ! countryString
.matches(".*\\).*")){
1025 remainingString
= countryString
;
1028 remainingString
= null;
1030 makeSingleCountry(state
, taxonNumber
, taxon
, nameUsedInSource
, countryString
.trim());
1031 } catch (UndefinedTransformerMethodException e
) {
1032 e
.printStackTrace();
1038 private void makeSingleCountry(CentralAfricaFernsImportState state
, String taxonNumber
, Taxon taxon
, TaxonNameBase nameUsedInSource
, String country
) throws UndefinedTransformerMethodException
{
1039 boolean areaDoubtful
= false;
1040 Distribution distribution
= Distribution
.NewInstance(null, PresenceTerm
.PRESENT());
1041 Reference sourceReference
= this.sourceReference
;
1042 distribution
.addSource(taxonNumber
, "Distribution_Country", sourceReference
, null, nameUsedInSource
, null);
1043 NamedArea area
= null;
1045 if (StringUtils
.isBlank(country
)){
1048 country
= country
.trim();
1050 if (country
.startsWith("?")){
1051 areaDoubtful
= true;
1052 country
= country
.substring(1).trim();
1055 country
= makeCountryStatus(state
, country
, distribution
);
1058 country
= makeCountryBrackets(state
, taxonNumber
, taxon
, nameUsedInSource
, country
);
1059 String countryWithoutIslands
= null;
1060 String countryWithoutDot
= null;
1061 if (country
.endsWith(" Isl.") || country
.endsWith(" isl.") ){
1062 countryWithoutIslands
= country
.substring(0, country
.length()-5);
1064 if (country
.endsWith(".")){
1065 countryWithoutDot
= country
.substring(0, country
.length()-1);
1067 if (country
.endsWith("*")){
1068 country
= country
.substring(0, country
.length()-1);
1070 if (country
.endsWith("Islands")){
1071 country
= country
.replace("Islands", "Is.");
1076 if (TdwgArea
.isTdwgAreaLabel(country
)){
1078 area
= TdwgArea
.getAreaByTdwgLabel(country
);
1079 }else if (TdwgArea
.isTdwgAreaLabel(countryWithoutIslands
)){
1081 area
= TdwgArea
.getAreaByTdwgLabel(countryWithoutIslands
);
1082 }else if (TdwgArea
.isTdwgAreaLabel(countryWithoutDot
)){
1084 area
= TdwgArea
.getAreaByTdwgLabel(countryWithoutDot
);
1085 }else if ( (area
= state
.getTransformer().getNamedAreaByKey(country
)) != null) {
1087 }else if (WaterbodyOrCountry
.isWaterbodyOrCountryLabel(country
)){
1089 area
= WaterbodyOrCountry
.getWaterbodyOrCountryByLabel(country
);
1092 NamedAreaLevel level
= null;
1093 NamedAreaType areaType
= null;
1095 UUID uuid
= state
.getTransformer().getNamedAreaUuid(country
);
1097 logger
.error(taxonNumber
+ " - Unknown country: " + country
);
1099 area
= getNamedArea(state
, uuid
, country
, country
, country
, areaType
, level
);
1102 distribution
.setArea(area
);
1103 if (areaDoubtful
== true){
1104 if (distribution
.getStatus().equals(PresenceTerm
.PRESENT())){
1105 distribution
.setStatus(PresenceTerm
.PRESENT_DOUBTFULLY());
1108 TaxonDescription description
= getTaxonDescription(taxon
, false, true);
1109 description
.addElement(distribution
);
1118 Reference sourceReference
= null;
1119 private Reference
getFernsSourceReference(CentralAfricaFernsImportState state
) {
1120 // if (sourceReference == null || true){
1121 Reference tmpReference
= state
.getConfig().getSourceReference();
1122 sourceReference
= getReferenceService().find(tmpReference
.getUuid());
1124 return sourceReference
;
1128 private String
makeCountryBrackets(CentralAfricaFernsImportState state
, String taxonNumber
, Taxon taxon
, TaxonNameBase nameUsedInSource
, String country
) {
1129 String
[] split
= (country
+ " ").split("\\(.*\\)");
1130 if (split
.length
== 2){
1131 String bracket
= country
.substring(split
[0].length()+1, country
.indexOf(")"));
1132 country
= split
[0].trim();
1133 makeCountries(state
, taxonNumber
, taxon
, nameUsedInSource
, bracket
, null, null);
1134 }else if (split
.length
==1){
1137 logger
.warn("Illegal length");
1142 private String
makeCountryStatus(CentralAfricaFernsImportState state
, String country
, Distribution distribution
) throws UndefinedTransformerMethodException
{
1143 PresenceTerm status
= null;
1144 String
[] split
= country
.split(" - ");
1146 if (split
.length
== 2){
1147 country
= split
[0].trim();
1148 String statusString
= split
[1];
1149 statusString
= statusString
.replace(".", "");
1150 status
= state
.getTransformer().getPresenceTermByKey(statusString
);
1151 if (status
== null){
1152 logger
.warn("No status found: "+ statusString
);
1154 // UUID uuid = null;
1155 // status = getPresenceTerm(state, uuid, statusString, statusString, null);
1156 }else if (split
.length
== 1){
1159 logger
.warn("Invalid length: " + split
.length
);
1161 if (status
!= null){
1162 distribution
.setStatus(status
);
1171 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
1174 protected boolean doCheck(CentralAfricaFernsImportState state
){
1175 IOValidator
<CentralAfricaFernsImportState
> validator
= new CentralAfricaFernsTaxonImportValidator();
1176 return validator
.validate(state
);
1180 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1183 protected boolean isIgnore(CentralAfricaFernsImportState state
){
1184 return ! state
.getConfig().isDoRelTaxa();
1189 //************************ OLD **********************************************************
1192 * Adds the higherTaxon authors to the existingHigherTaxon authors if the higherTaxon has authors and
1193 * the existingHigherTaxon has no authors.
1194 * Returns false if both taxa have authors and the authors differ from each other.
1195 * @param higherTaxon
1196 * @param existingHigherTaxon
1198 private boolean mergeAuthors_old(Taxon higherTaxon
, Taxon existingHigherTaxon
) {
1199 NonViralName existingName
= CdmBase
.deproxy(higherTaxon
.getName(), NonViralName
.class);
1200 NonViralName newName
= CdmBase
.deproxy(existingHigherTaxon
.getName(), NonViralName
.class);
1201 if (existingName
== newName
){
1204 if (! newName
.hasAuthors()){
1207 if (! existingName
.hasAuthors()){
1208 existingName
.setCombinationAuthorTeam(newName
.getCombinationAuthorTeam());
1209 existingName
.setExCombinationAuthorTeam(newName
.getExCombinationAuthorTeam());
1210 existingName
.setBasionymAuthorTeam(newName
.getBasionymAuthorTeam());
1211 existingName
.setExBasionymAuthorTeam(newName
.getExBasionymAuthorTeam());
1214 boolean authorsAreSame
= true;
1215 authorsAreSame
&= getNomTitleNz(existingName
.getCombinationAuthorTeam()).equals(getNomTitleNz(newName
.getCombinationAuthorTeam()));
1216 authorsAreSame
&= getNomTitleNz(existingName
.getExCombinationAuthorTeam()).equals(getNomTitleNz(newName
.getExCombinationAuthorTeam()));
1217 authorsAreSame
&= getNomTitleNz(existingName
.getBasionymAuthorTeam()).equals(getNomTitleNz(newName
.getBasionymAuthorTeam()));
1218 authorsAreSame
&= getNomTitleNz(existingName
.getExBasionymAuthorTeam()).equals(getNomTitleNz(newName
.getExBasionymAuthorTeam()));
1219 return authorsAreSame
;
1225 * Returns the nomenclatural title of the author. Returns empty string if author is <code>null</code> or
1226 * titleCache is <code>null</code>.
1230 private String
getNomTitleNz(INomenclaturalAuthor author
) {
1231 if (author
!= null){
1232 return CdmUtils
.Nz(author
.getNomenclaturalTitle());
1238 private Taxon
getExistingHigherTaxon_old(Taxon child
, Taxon higherTaxon
) {
1239 int countNodes
= child
.getTaxonNodes().size();
1240 if (countNodes
< 1){
1242 }else if (countNodes
> 1){
1243 throw new IllegalStateException("Multiple nodes exist for child taxon. This is an invalid state.");
1245 TaxonNode childNode
= child
.getTaxonNodes().iterator().next();
1246 TaxonNode parentNode
= childNode
.getParent();
1247 if (parentNode
!= null){
1248 String existingParentTitle
= parentNode
.getTaxon().getName().getTitleCache();
1249 String newParentTitle
= higherTaxon
.getName().getTitleCache();
1250 if (existingParentTitle
.equals(newParentTitle
)){
1251 return parentNode
.getTaxon();
1261 * Tests if this the child taxon already is a child of the higher taxon.
1263 * @param higherTaxon
1266 private boolean includedRelationshipExists_Old(Taxon child
, Taxon higherTaxon
) {
1267 int countNodes
= higherTaxon
.getTaxonNodes().size();
1268 if (countNodes
< 1){
1270 }else if (countNodes
> 1){
1271 throw new IllegalStateException("Multiple nodes exist for higher taxon. This is an invalid state.");
1273 TaxonNode higherNode
= higherTaxon
.getTaxonNodes().iterator().next();
1274 return childExists_old(child
, higherNode
);
1280 private boolean childExists_old(Taxon child
, TaxonNode higherNode
) {
1281 for (TaxonNode childNode
: higherNode
.getChildNodes()){
1282 String existingChildTitle
= childNode
.getTaxon().getName().getTitleCache();
1283 String newChildTitle
= child
.getName().getTitleCache();
1284 if (existingChildTitle
.equals(newChildTitle
)){