2 * Copyright (C) 2009 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.
9 package eu
.etaxonomy
.cdm
.io
.pesi
.out
;
11 import java
.sql
.Connection
;
12 import java
.sql
.PreparedStatement
;
13 import java
.sql
.ResultSet
;
14 import java
.sql
.SQLException
;
15 import java
.sql
.Types
;
16 import java
.util
.ArrayList
;
17 import java
.util
.EnumSet
;
18 import java
.util
.HashMap
;
19 import java
.util
.Iterator
;
20 import java
.util
.List
;
23 import java
.util
.UUID
;
24 import java
.util
.regex
.Matcher
;
25 import java
.util
.regex
.Pattern
;
27 import org
.apache
.commons
.lang
.StringUtils
;
28 import org
.apache
.log4j
.Logger
;
29 import org
.springframework
.stereotype
.Component
;
30 import org
.springframework
.transaction
.TransactionStatus
;
32 import eu
.etaxonomy
.cdm
.api
.service
.TaxonServiceImpl
;
33 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
34 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
35 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
36 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbConstantMapper
;
37 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbLastActionMapper
;
38 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbObjectMapper
;
39 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbStringMapper
;
40 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.IdMapper
;
41 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.MethodMapper
;
42 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.ObjectChangeMapper
;
43 import eu
.etaxonomy
.cdm
.io
.pesi
.erms
.ErmsTransformer
;
44 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
45 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
46 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
47 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
48 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
49 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
50 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
51 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
52 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
53 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
54 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignationStatus
;
55 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
56 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
57 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
58 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
59 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
60 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
61 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
62 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
63 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymType
;
64 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
65 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
66 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
67 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
68 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
69 import eu
.etaxonomy
.cdm
.strategy
.cache
.HTMLTagRules
;
70 import eu
.etaxonomy
.cdm
.strategy
.cache
.TagEnum
;
71 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INonViralNameCacheStrategy
;
72 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.TaxonNameDefaultCacheStrategy
;
73 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.ZooNameNoMarkerCacheStrategy
;
76 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
77 * Inserts into DataWarehouse database table <code>Taxon</code>.
78 * It is divided into four phases:<p><ul>
79 * <li>Phase 1: Export of all {@link eu.etaxonomy.cdm.model.name.TaxonName TaxonNames} except some data exported in the following phases.
80 * <li>Phase 2: Export of additional data: ParentTaxonFk and TreeIndex.
81 * <li>Phase 3: Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
82 * <li>Phase 4: Export of Inferred Synonyms.</ul>
88 public class PesiTaxonExport
extends PesiExportBase
{
90 private static final long serialVersionUID
= -3412722058790200078L;
91 private static final Logger logger
= Logger
.getLogger(PesiTaxonExport
.class);
93 private static final Class
<?
extends CdmBase
> standardMethodParameter
= TaxonBase
.class;
95 private static int modCount
= 1000;
96 private static final String dbTableName
= "Taxon";
97 private static final String dbTableNameSynRel
= "RelTaxon";
98 private static final String dbTableAdditionalSourceRel
= "AdditionalTaxonSource";
100 private static final String pluralString
= "Taxa";
101 private static final String parentPluralString
= "Taxa";
102 private static final String pluralStringNames
= "Names";
104 // private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmts;
105 private PreparedStatement parentTaxonFkStmt
;
106 private PreparedStatement rankTypeExpertsUpdateStmt
;
107 private PreparedStatement rankUpdateStmt
;
108 private Integer kingdomFk
;
110 private static ExtensionType lastActionExtensionType
;
111 private static ExtensionType lastActionDateExtensionType
;
112 private static ExtensionType expertNameExtensionType
;
113 private static ExtensionType speciesExpertNameExtensionType
;
114 private static ExtensionType cacheCitationExtensionType
;
116 public static TaxonNameDefaultCacheStrategy zooNameStrategy
= ZooNameNoMarkerCacheStrategy
.NewInstance();
117 public static TaxonNameDefaultCacheStrategy nonViralNameStrategy
= TaxonNameDefaultCacheStrategy
.NewInstance();
118 private static int currentTaxonId
;
128 public PesiTaxonExport() {
133 public Class
<?
extends CdmBase
> getStandardMethodParameter() {
134 return standardMethodParameter
;
138 protected void doInvoke(PesiExportState state
) {
140 logger
.info("*** Started Making " + pluralString
+ " ...");
142 initPreparedStatements(state
);
144 // Stores whether this invoke was successful or not.
145 boolean success
= true;
147 // PESI: Clear the database table Taxon.
150 // Get specific mappings: (CDM) Taxon -> (PESI) Taxon
151 PesiExportMapping mapping
= getMapping();
152 PesiExportMapping synonymRelMapping
= getSynRelMapping();
153 PesiExportMapping additionalSourceMapping
= getAdditionalSourceMapping(state
);
155 // Initialize the db mapper
156 mapping
.initialize(state
);
157 synonymRelMapping
.initialize(state
);
158 additionalSourceMapping
.initialize(state
);
160 // Find extensionTypes
161 lastActionExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.uuidExtLastAction
);
162 lastActionDateExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.uuidExtLastActionDate
);
163 expertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.uuidExtExpertName
);
164 speciesExpertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.uuidExtSpeciesExpertName
);
165 cacheCitationExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.uuidExtCacheCitation
);
168 success
&= doPhase01(state
, mapping
, additionalSourceMapping
);
170 //"PHASE 1b: Handle names without taxa ...
171 success
&= doPhase01b_Names(state
, additionalSourceMapping
);
173 // 2nd Round: Add ParentTaxonFk to each taxon
174 success
&= doPhase02(state
);
176 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
177 success
&= doPhase03(state
);
179 // 4nd Round: Add TreeIndex to each taxon
180 success
&= doPhase04(state
);
182 //"PHASE 5: Creating Inferred Synonyms...
183 success
&= doPhase05(state
, mapping
, synonymRelMapping
);
185 logger
.info("*** Finished Making " + pluralString
+ " ..." + getSuccessString(success
));
188 state
.getResult().addError("An error occurred in PesiTaxonExport.doInvoke. Success = false");
191 } catch (Exception e
) {
193 logger
.error(e
.getMessage());
194 state
.getResult().addException(e
);
199 private void initPreparedStatements(PesiExportState state
) throws SQLException
{
200 // initTreeIndexStatement(state);
201 initRankExpertsUpdateStmt(state
);
202 initRankUpdateStatement(state
);
204 initParentFkStatement(state
);
207 // // Prepare TreeIndex-And-KingdomFk-Statement
208 // private void initTreeIndexStatement(PesiExportState state) throws SQLException {
209 // Connection connection = state.getConfig().getDestination().getConnection();
210 // String parentTaxonFk_TreeIndex_KingdomFkSql = "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?";
211 // parentTaxonFk_TreeIndex_KingdomFkStmt = connection.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql);
214 // Prepare TreeIndex-And-KingdomFk-Statement
215 private void initParentFkStatement(PesiExportState state
) throws SQLException
{
216 Connection connection
= state
.getConfig().getDestination().getConnection();
217 String parentTaxonFkSql
= "UPDATE Taxon SET ParentTaxonFk = ? WHERE TaxonId = ?";
218 parentTaxonFkStmt
= connection
.prepareStatement(parentTaxonFkSql
);
221 private void initRankUpdateStatement(PesiExportState state
) throws SQLException
{
222 Connection connection
= state
.getConfig().getDestination().getConnection();
223 String rankSql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
224 rankUpdateStmt
= connection
.prepareStatement(rankSql
);
227 private void initRankExpertsUpdateStmt(PesiExportState state
) throws SQLException
{
228 // String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
229 // "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
230 //TODO handle experts GUIDs
231 Connection connection
= state
.getConfig().getDestination().getConnection();
233 String sql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
234 " WHERE TaxonId = ?";
235 rankTypeExpertsUpdateStmt
= connection
.prepareStatement(sql
);
238 private boolean doPhase01(PesiExportState state
, PesiExportMapping mapping
, PesiExportMapping additionalSourceMapping
){
242 boolean success
= true;
243 // Get the limit for objects to save within a single transaction.
244 int limit
= state
.getConfig().getLimitSave();
246 logger
.info("PHASE 1: Export Taxa...limit is " + limit
);
248 TransactionStatus txStatus
= startTransaction(true);
249 if (logger
.isDebugEnabled()) {
250 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
251 logger
.info("Taking snapshot at the beginning of phase 1 of taxonExport");
252 //ProfilerController.memorySnapshot();
255 int partitionCount
= 0;
256 List
<TaxonBase
<?
>> list
;
257 while ((list
= getNextTaxonPartition(null, limit
, partitionCount
++, null)) != null ) {
259 logger
.debug("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
261 for (TaxonBase
<?
> taxon
: list
) {
262 doCount(count
++, modCount
, pluralString
);
263 TaxonName taxonName
= taxon
.getName();
265 TaxonName nvn
= CdmBase
.deproxy(taxonName
);
266 if (! nvn
.isProtectedTitleCache()){
267 nvn
.setTitleCache(null, false);
269 if (! nvn
.isProtectedNameCache()){
270 nvn
.setNameCache(null, false);
272 if (! nvn
.isProtectedFullTitleCache()){
273 nvn
.setFullTitleCache(null, false);
275 if (! nvn
.isProtectedAuthorshipCache()){
276 nvn
.setAuthorshipCache(null, false);
279 if (nvn
.getRank().equals(Rank
.KINGDOM())){
280 if(taxon
.isInstanceOf(Taxon
.class)){
281 String treeIndex
= ((Taxon
)taxon
).getTaxonNodes().iterator().next().treeIndex();
282 Integer kingdomId
= PesiTransformer
.pesiKingdomId(nvn
.getGenusOrUninomial());
283 state
.getTreeIndexKingdomMap().put(treeIndex
, kingdomId
);
285 logger
.warn("Kingdom taxon is not of class Taxon but " + taxon
.getClass().getSimpleName() + ": " + nvn
.getGenusOrUninomial());
288 }catch(NullPointerException e
){
289 logger
.error(nvn
.getTitleCache() + " has no Rank!");
290 System
.err
.println(nvn
.getTitleCache() + " has no Rank!");
293 success
&= mapping
.invoke(taxon
);
295 if (nvn
.getNomenclaturalReference() != null || StringUtils
.isNotBlank(nvn
.getNomenclaturalMicroReference() )){
296 additionalSourceMapping
.invoke(taxon
);
299 //TODO switch on again, leads to some warnings in ERMS for taxa of not correctly handled kingdoms
300 validatePhaseOne(taxon
, nvn
);
303 // Commit transaction
304 commitTransaction(txStatus
);
305 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
+ " (Phase 01)");
308 // Start new transaction
309 txStatus
= startTransaction(true);
310 if (logger
.isDebugEnabled()) {
311 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
315 logger
.debug("No " + pluralString
+ " left to fetch.");
317 // Commit transaction
318 commitTransaction(txStatus
);
324 private void validatePhaseOne(TaxonBase
<?
> taxon
, TaxonName taxonName
) {
326 // Check whether some rules are violated
327 String genusOrUninomial
= taxonName
.getGenusOrUninomial();
328 String specificEpithet
= taxonName
.getSpecificEpithet();
329 String infraSpecificEpithet
= taxonName
.getInfraSpecificEpithet();
330 String infraGenericEpithet
= taxonName
.getInfraGenericEpithet();
331 Rank rank
= taxonName
.getRank();
333 //as kingdomFk can not be defined in Phase 01 the below code was switched to use the CDM rank. This may be changed if we move validation to Phase03 or later
334 // Integer rankFk = getRankFk(taxonName, taxonName.getNameType());
335 // if (rankFk == null) {
336 // logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
339 // Check whether infraGenericEpithet is set correctly
340 // 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
341 // 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
343 int ancestorLevel
= 0;
344 if (taxonName
.getRank().equals(Rank
.SUBSPECIES())) {
345 // The accepted taxon two rank levels above should be of rank subgenus
348 if (taxonName
.getRank().equals(Rank
.SPECIES())) {
349 // The accepted taxon one rank level above should be of rank subgenus
352 if (ancestorLevel
> 0) {
353 if (validateAncestorOfSpecificRank(taxon
, ancestorLevel
, Rank
.SUBGENUS())) {
354 // The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
355 if (infraGenericEpithet
== null) {
356 logger
.warn("InfraGenericEpithet for (sub)species of infrageneric taxon does not exist even though it should (also valid for Botanical Names?) for: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
357 // maybe the taxon could be named here
362 if (infraGenericEpithet
== null && rank
.isInfraGenericButNotSpeciesGroup()) {
363 logger
.warn("InfraGenericEpithet was not determined although it should exist for infra generic names: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
365 if (specificEpithet
!= null && (rank
.isInfraGenericButNotSpeciesGroup()||rank
.isGenus()||rank
.isSupraGeneric())) {
366 logger
.warn("SpecificEpithet was determined for rank " + rank
.getTitleCache() + " although it should only exist for species aggregates, species or infraspecific taxa: TaxonName " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
368 if (infraSpecificEpithet
!= null && !rank
.isInfraSpecific()) {
369 String message
= "InfraSpecificEpithet '" +infraSpecificEpithet
+ "' was determined for rank " + rank
.getTitleCache() + " although it should only exist for rank species and higher: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")";
370 if (StringUtils
.isNotBlank(infraSpecificEpithet
)){
371 logger
.warn(message
);
373 logger
.warn(message
);
377 if (infraSpecificEpithet
!= null && specificEpithet
== null) {
378 logger
.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
380 if (genusOrUninomial
== null) {
381 logger
.warn("GenusOrUninomial was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
386 * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists
388 private boolean doPhase02(PesiExportState state
) {
391 boolean success
= true;
392 if (! state
.getConfig().isDoParentAndBiota()){
393 logger
.info ("Ignore PHASE 2: Make ParentFk and Biota...");
397 // Get the limit for objects to save within a single transaction.
398 int limit
= state
.getConfig().getLimitSave();
402 logger
.info("PHASE 2: Make ParentFk and Biota ... limit is " + limit
);
404 TransactionStatus txStatus
= startTransaction(true);
405 int partitionCount
= 0;
407 // ProfilerController.memorySnapshot();
409 while ((list
= getNextTaxonPartition(Taxon
.class, limit
, partitionCount
++, null)) != null ) {
411 if(logger
.isDebugEnabled()) {
412 logger
.info("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
414 for (Taxon taxon
: list
) {
415 for (TaxonNode node
: taxon
.getTaxonNodes()){
416 doCount(count
++, modCount
, pluralString
);
417 TaxonNode parentNode
= node
.getParent();
418 if (parentNode
!= null && isPesiTaxon(parentNode
.getTaxon())){//exclude root taxa and unpublished parents (relevant for "Valueless" parent for E+M Rubus taxa). Usually a parent should not be unpublished
419 int childId
= state
.getDbId( taxon
);
420 int parentId
= state
.getDbId(parentNode
.getTaxon());
421 success
&= invokeParentTaxonFk(parentId
, childId
);
426 // Commit transaction
427 commitTransaction(txStatus
);
428 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
+ " (Phase 2)");
431 txStatus
= startTransaction(true);
432 if (logger
.isDebugEnabled()){
433 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
436 logger
.debug("No " + pluralString
+ " left to fetch.");
438 // Commit transaction
439 commitTransaction(txStatus
);
445 * Inserts the Biota Taxon if not yet exists.
447 private void insertBiota(PesiExportState state
) {
449 ResultSet rs
= state
.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");
450 if (rs
.next() == false){
451 int biotaId
= state
.getConfig().getNameIdStart() -1 ;
452 String sqlInsertBiota
= "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +
453 " VALUES (" + biotaId
+ ", 0, 0, 'Superdomain', 'Biota', 'Biota', '<i>Biota</i>', 'Biota', '<i>Biota</i>', 1 , 'accepted')";
454 state
.getConfig().getDestination().update(sqlInsertBiota
);
457 } catch (SQLException e
) {
458 logger
.warn ("Biota could not be requested or inserted");
462 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
463 private boolean doPhase03(PesiExportState state
) {
466 boolean success
= true;
467 if (! state
.getConfig().isDoTreeIndex()){
468 logger
.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
472 addValuelessTaxonToKingdomMap(state
);
474 // Get the limit for objects to save within a single transaction.
475 int limit
= state
.getConfig().getLimitSave();
477 logger
.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
478 // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
481 TransactionStatus txStatus
= startTransaction(true);
482 if (logger
.isDebugEnabled()) {
483 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
485 int partitionCount
= 0;
486 @SuppressWarnings("rawtypes")
487 List
<TaxonBase
> list
;
488 while ((list
= getNextTaxonPartition(TaxonBase
.class, limit
, partitionCount
++, null)) != null) {
490 if (logger
.isDebugEnabled()) {
491 logger
.debug("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
493 for (TaxonBase
<?
> taxon
: list
) {
494 TaxonName taxonName
= CdmBase
.deproxy(taxon
.getName());
495 // Determine expertFk
496 // Integer expertFk = makeExpertFk(state, taxonName);
498 // // Determine speciesExpertFk
499 // Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
501 doCount(count
++, modCount
, pluralString
);
502 Integer typeNameFk
= getTypeNameFk(taxonName
, state
);
503 Integer kingdomFk
= findKingdomIdFromTreeIndex(taxon
, state
);
504 Integer rankFk
= getRankFk(taxonName
, kingdomFk
);
506 invokeRankDataAndTypeNameFkAndKingdomFk(taxonName
, state
.getDbId(taxon
),
507 typeNameFk
, kingdomFk
, rankFk
, state
);
510 // Commit transaction
511 commitTransaction(txStatus
);
512 if (logger
.isDebugEnabled()){logger
.debug("Committed transaction.");}
513 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
+ " (Phase 3)");
517 txStatus
= startTransaction(true);
518 if (logger
.isDebugEnabled()) {
519 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
522 logger
.debug("No " + pluralString
+ " left to fetch.");
524 // Commit transaction
525 commitTransaction(txStatus
);
527 if (logger
.isDebugEnabled()){
528 logger
.debug("Committed transaction.");
529 logger
.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount
);
530 //ProfilerController.memorySnapshot();
535 private void addValuelessTaxonToKingdomMap(PesiExportState state
) {
536 TransactionStatus txStatus
= startTransaction();
537 Taxon valuelessTaxon
= (Taxon
)getTaxonService().find(PesiTransformer
.uuidTaxonValuelessEuroMed
);
538 if (valuelessTaxon
!= null){
539 String treeIndex
= valuelessTaxon
.getTaxonNodes().iterator().next().treeIndex();
540 Integer kingdomId
= PesiTransformer
.pesiKingdomId("Plantae");
541 state
.getTreeIndexKingdomMap().put(treeIndex
, kingdomId
);
543 commitTransaction(txStatus
);
546 // 4th round: Add TreeIndex to each taxon
547 private boolean doPhase04(PesiExportState state
) {
548 boolean success
= true;
550 logger
.info("PHASE 4: Make TreeIndex ... ");
552 //TODO test if possible to move to phase 02
553 String sql
= " UPDATE Taxon SET ParentTaxonFk = (SELECT TaxonId FROM Taxon WHERE RankFk = 0) " +
554 " WHERE (RankFk = 10) and TaxonStatusFk = 1 ";
555 state
.getConfig().getDestination().update(sql
);
557 state
.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
559 logger
.info("PHASE 4: Make TreeIndex DONE");
564 private static Integer
findKingdomIdFromTreeIndex(TaxonBase
<?
> taxonBase
, PesiExportState state
) {
566 if (taxonBase
instanceof Synonym
){
567 taxon
= ((Synonym
) taxonBase
).getAcceptedTaxon();
569 taxon
= checkPseudoOrRelatedTaxon((Taxon
)taxonBase
);
572 NomenclaturalCode nomenclaturalCode
= taxonBase
.getName().getNameType();
573 logger
.warn("Taxon is synonym with no accepted taxon attached: " + taxonBase
.getTitleCache() + ". The kingdom is taken from the nomenclatural code: " + PesiTransformer
.nomenclaturalCode2Kingdom(nomenclaturalCode
) );
574 return PesiTransformer
.nomenclaturalCode2Kingdom(nomenclaturalCode
);
576 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
577 if (nodes
.isEmpty()){
578 NomenclaturalCode nomenclaturalCode
= taxon
.getName().getNameType();
579 logger
.warn("The taxon has no nodes: " + taxon
.getTitleCache() + ". The kingdom is taken from the nomenclatural code: " + PesiTransformer
.nomenclaturalCode2Kingdom(nomenclaturalCode
));
580 return PesiTransformer
.nomenclaturalCode2Kingdom(nomenclaturalCode
);
583 logger
.warn("The taxon has more then 1 taxon node: " + taxon
.getTitleCache() + ". Take arbitrary one.");
585 String treeIndex
= nodes
.iterator().next().treeIndex();
587 Pattern pattern
= Pattern
.compile("#t[0-9]+#([0-9]+#){3}");
588 Matcher matcher
= pattern
.matcher(treeIndex
);
589 Integer kingdomID
= null;
591 String treeIndexKingdom
= matcher
.group(0);
592 kingdomID
= state
.getTreeIndexKingdomMap().get(treeIndexKingdom
);
594 if (kingdomID
== null){
595 pattern
= Pattern
.compile("#t[0-9]+#([0-9]+#){2}");
596 matcher
= pattern
.matcher(treeIndex
);
598 String treeIndexKingdom
= matcher
.group(0);
599 Map
<String
, Integer
> map
= state
.getTreeIndexKingdomMap();
600 kingdomID
= map
.get(treeIndexKingdom
);
603 if(Rank
.DOMAIN().equals(taxon
.getName().getRank())){
606 if(kingdomID
== null){
607 logger
.warn("Kingdom could not be defined for treeindex " + treeIndex
);
614 private static Taxon
checkPseudoOrRelatedTaxon(Taxon taxon
) {
615 if (!taxon
.getTaxonNodes().isEmpty()){
617 }else if(hasPseudoTaxonRelationship(taxon
)){
618 return acceptedPseudoTaxon(taxon
);
619 }else if(isMisappliedNameOrProParteSynonym(taxon
)){
620 return acceptedTaxonConcept(taxon
);
626 private static Taxon
acceptedPseudoTaxon(Taxon taxon
) {
627 for (TaxonRelationship rel
: taxon
.getRelationsFromThisTaxon()){
628 if (TaxonRelationshipType
.pseudoTaxonUuids().contains(rel
.getType().getUuid())){
629 return rel
.getToTaxon();
635 private static Taxon
acceptedTaxonConcept(Taxon taxon
) {
636 for (TaxonRelationship rel
: taxon
.getRelationsFromThisTaxon()){
637 if (TaxonRelationshipType
.misappliedNameUuids().contains(rel
.getType().getUuid())||
638 TaxonRelationshipType
.proParteOrPartialSynonymUuids().contains(rel
.getType().getUuid())){
639 return rel
.getToTaxon();
645 private static boolean hasPseudoTaxonRelationship(Taxon taxon
) {
646 for (TaxonRelationship rel
: taxon
.getRelationsFromThisTaxon()){
647 if (TaxonRelationshipType
.pseudoTaxonUuids().contains(rel
.getType().getUuid())){
654 private static boolean isMisappliedNameOrProParteSynonym(Taxon taxon
) {
655 for (TaxonRelationship rel
: taxon
.getRelationsFromThisTaxon()){
656 if (TaxonRelationshipType
.misappliedNameUuids().contains(rel
.getType().getUuid())||
657 TaxonRelationshipType
.proParteOrPartialSynonymUuids().contains(rel
.getType().getUuid())){
664 // "PHASE 5: Creating Inferred Synonyms..."
665 private boolean doPhase05(PesiExportState state
, PesiExportMapping mapping
, PesiExportMapping synRelMapping
) {
668 boolean success
= true;
669 // Get the limit for objects to save within a single transaction.
670 if (! state
.getConfig().isDoInferredSynonyms()){
671 logger
.info ("Ignore PHASE 5: Creating Inferred Synonyms...");
675 int limit
= state
.getConfig().getLimitSave();
676 // Create inferred synonyms for accepted taxa
677 logger
.info("PHASE 5: Creating Inferred Synonyms...");
679 // Determine the count of elements in data warehouse database table Taxon
680 currentTaxonId
= determineTaxonCount(state
);
685 int pageSize
= limit
/10;
687 String inferredSynonymPluralString
= "Inferred Synonyms";
690 TransactionStatus txStatus
= startTransaction(true);
691 if (logger
.isDebugEnabled()) {
692 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
695 List
<TaxonBase
> taxonList
= null;
696 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", "*", Rank
.SPECIES(), pageSize
, pageNumber
)).size() > 0) {
698 Map
<Integer
, TaxonName
> inferredSynonymsDataToBeSaved
= new HashMap
<>();
700 if (logger
.isDebugEnabled()) {
701 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
703 inferredSynonymsDataToBeSaved
.putAll(createInferredSynonymsForTaxonList(state
, mapping
,
704 synRelMapping
, taxonList
));
706 doCount(count
+= taxonList
.size(), modCount
, inferredSynonymPluralString
);
707 // Commit transaction
708 commitTransaction(txStatus
);
709 if (logger
.isDebugEnabled()){logger
.debug("Committed transaction.");}
710 logger
.info("Exported " + (taxonList
.size()) + " " + inferredSynonymPluralString
+ ". Total: " + count
);
713 // Save Rank Data and KingdomFk for inferred synonyms
714 for (Integer taxonFk
: inferredSynonymsDataToBeSaved
.keySet()) {
715 TaxonName taxonName
= inferredSynonymsDataToBeSaved
.get(taxonFk
);
716 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved
.get(taxonFk
), taxonFk
, kingdomFk
, state
);
720 txStatus
= startTransaction(true);
721 if (logger
.isDebugEnabled()) {
722 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
725 // Increment pageNumber
729 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", "*", Rank
.SUBSPECIES(), pageSize
, pageNumber
)).size() > 0) {
730 Map
<Integer
, TaxonName
> inferredSynonymsDataToBeSaved
= new HashMap
<>();
732 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
733 inferredSynonymsDataToBeSaved
.putAll(createInferredSynonymsForTaxonList(state
, mapping
,
734 synRelMapping
, taxonList
));
736 doCount(count
+= taxonList
.size(), modCount
, inferredSynonymPluralString
);
737 // Commit transaction
738 commitTransaction(txStatus
);
739 logger
.debug("Committed transaction.");
740 logger
.info("Exported " + taxonList
.size()+ " " + inferredSynonymPluralString
+ ". Total: " + count
);
743 // Save Rank Data and KingdomFk for inferred synonyms
744 for (Integer taxonFk
: inferredSynonymsDataToBeSaved
.keySet()) {
745 TaxonName taxonName
= inferredSynonymsDataToBeSaved
.get(taxonFk
);
746 invokeRankDataAndKingdomFk(taxonName
, taxonFk
, kingdomFk
, state
);
750 txStatus
= startTransaction(true);
751 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
753 // Increment pageNumber
755 inferredSynonymsDataToBeSaved
= null;
757 if (taxonList
.size() == 0) {
758 logger
.info("No " + parentPluralString
+ " left to fetch.");
762 // logger.warn("Taking snapshot at the end of phase 5 of taxonExport");
763 // ProfilerController.memorySnapshot();
765 // Commit transaction
766 commitTransaction(txStatus
);
768 logger
.debug("Taking snapshot at the end of phase 5 after gc() of taxonExport");
769 //ProfilerController.memorySnapshot();
770 logger
.debug("Committed transaction.");
774 private Map
<Integer
, TaxonName
> createInferredSynonymsForTaxonList(PesiExportState state
,
775 PesiExportMapping mapping
, PesiExportMapping synRelMapping
, List
<TaxonBase
> taxonList
) {
778 Classification classification
= null;
779 List
<Synonym
> inferredSynonyms
= null;
780 boolean localSuccess
= true;
782 Map
<Integer
, TaxonName
> inferredSynonymsDataToBeSaved
= new HashMap
<>();
784 for (TaxonBase
<?
> taxonBase
: taxonList
) {
786 if (taxonBase
.isInstanceOf(Taxon
.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
787 acceptedTaxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
788 TaxonName taxonName
= acceptedTaxon
.getName();
790 if (taxonName
.isZoological()) {
791 kingdomFk
= findKingdomIdFromTreeIndex(taxonBase
, state
);
793 Set
<TaxonNode
> taxonNodes
= acceptedTaxon
.getTaxonNodes();
794 TaxonNode singleNode
= null;
796 if (taxonNodes
.size() > 0) {
797 // Determine the classification of the current TaxonNode
799 singleNode
= taxonNodes
.iterator().next();
800 if (singleNode
!= null) {
801 classification
= singleNode
.getClassification();
803 logger
.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() +")");
806 // Classification could not be determined directly from this TaxonNode
807 // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
808 if (taxonNodes
.size() == 0) {
809 //logger.error("Classification could not be determined directly from this Taxon: " + acceptedTaxon.getUuid() + " is misapplication? "+acceptedTaxon.isMisapplication()+ "). The classification of the last taxon is used");
813 if (classification
!= null) {
815 TaxonName name
= acceptedTaxon
.getName();
816 //if (name.isSpecies() || name.isInfraSpecific()){
817 inferredSynonyms
= getTaxonService().createAllInferredSynonyms(acceptedTaxon
, classification
, true);
819 // inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymType.INFERRED_GENUS_OF());
820 if (inferredSynonyms
!= null) {
821 for (Synonym synonym
: inferredSynonyms
) {
822 // TaxonName synonymName = synonym.getName();
823 MarkerType markerType
=getUuidMarkerType(PesiTransformer
.uuidMarkerGuidIsMissing
, state
);
824 synonym
.addMarker(Marker
.NewInstance(markerType
, true));
825 // Both Synonym and its TaxonName have no valid Id yet
826 synonym
.setId(currentTaxonId
++);
829 localSuccess
&= mapping
.invoke(synonym
);
830 //get SynonymRelationship and export
831 if (synonym
.getAcceptedTaxon() == null ){
832 IdentifiableSource source
= synonym
.getSources().iterator().next();
833 if (source
.getIdNamespace().contains("Potential combination")){
834 acceptedTaxon
.addSynonym(synonym
, SynonymType
.POTENTIAL_COMBINATION_OF());
835 logger
.error(synonym
.getTitleCache() + " is not attached to " + acceptedTaxon
.getTitleCache() + " type is set to potential combination");
836 } else if (source
.getIdNamespace().contains("Inferred Genus")){
837 acceptedTaxon
.addSynonym(synonym
, SynonymType
.INFERRED_GENUS_OF());
838 logger
.error(synonym
.getTitleCache() + " is not attached to " + acceptedTaxon
.getTitleCache() + " type is set to inferred genus");
839 } else if (source
.getIdNamespace().contains("Inferred Epithet")){
840 acceptedTaxon
.addSynonym(synonym
, SynonymType
.INFERRED_EPITHET_OF());
841 logger
.error(synonym
.getTitleCache() + " is not attached to " + acceptedTaxon
.getTitleCache() + " type is set to inferred epithet");
843 acceptedTaxon
.addSynonym(synonym
, SynonymType
.INFERRED_SYNONYM_OF());
844 logger
.error(synonym
.getTitleCache() + " is not attached to " + acceptedTaxon
.getTitleCache() + " type is set to inferred synonym");
847 localSuccess
&= synRelMapping
.invoke(synonym
);
849 logger
.error("Synonym relationship export failed " + synonym
.getTitleCache() + " accepted taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
852 localSuccess
&= synRelMapping
.invoke(synonym
);
854 logger
.error("Synonym relationship export failed " + synonym
.getTitleCache() + " accepted taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
856 logger
.info("Synonym relationship successfully exported: " + synonym
.getTitleCache() + " " +acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
860 inferredSynonymsDataToBeSaved
.put(synonym
.getId(), synonym
.getName());
864 logger
.error(e
.getMessage());
868 logger
.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() + ")");
871 // logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
874 logger
.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase
.getUuid() + " (" + taxonBase
.getTitleCache() + ")");
877 return inferredSynonymsDataToBeSaved
;
881 * Handles names that do not appear in taxa
885 private boolean doPhase01b_Names(PesiExportState state
, PesiExportMapping additionalSourceMapping
) {
887 boolean success
= true;
888 if (! state
.getConfig().isDoPureNames()){
889 logger
.info ("Ignore PHASE 1b: PureNames");
894 PesiExportMapping mapping
= getPureNameMapping(state
);
895 mapping
.initialize(state
);
899 // Get the limit for objects to save within a single transaction.
900 int limit
= state
.getConfig().getLimitSave();
902 logger
.info("PHASE 1b: Export Pure Names ...");
904 TransactionStatus txStatus
= startTransaction(true);
905 logger
.info("Started new transaction for Pure Names. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
907 int partitionCount
= 0;
908 List
<TaxonName
> list
;
909 while ((list
= getNextPureNamePartition(null, limit
, partitionCount
++)) != null ) {
911 logger
.debug("Fetched " + list
.size() + pluralStringNames
+ " without taxa. Exporting...");
912 for (TaxonName taxonName
: list
) {
913 doCount(count
++, modCount
, pluralString
);
914 success
&= mapping
.invoke(taxonName
);
916 if (taxonName
.getNomenclaturalReference() != null || StringUtils
.isNotBlank(taxonName
.getNomenclaturalMicroReference() )){
917 additionalSourceMapping
.invoke(taxonName
);
921 // Commit transaction
922 commitTransaction(txStatus
);
923 logger
.debug("Committed transaction.");
924 logger
.info("Exported " + (count
- pastCount
) + " " + pluralStringNames
+ ". Total: " + count
+ ". Partition: " + partitionCount
);
928 txStatus
= startTransaction(true);
929 logger
.debug("Started new transaction for PureNames. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
931 logger
.debug("No " + pluralString
+ " left to fetch.");
933 // Commit transaction
934 commitTransaction(txStatus
);
935 logger
.debug("Committed transaction.");
936 } catch (Exception e
) {
937 logger
.error("Error occurred in pure name export");
945 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
946 * @param state The {@link PesiExportState PesiExportState}.
949 private Integer
determineTaxonCount(PesiExportState state
) {
950 Integer result
= null;
951 PesiExportConfigurator pesiConfig
= state
.getConfig();
954 Source destination
= pesiConfig
.getDestination();
955 sql
= "SELECT max(taxonId) FROM Taxon";
956 destination
.setQuery(sql
);
957 ResultSet resultSet
= destination
.getResultSet();
960 result
= resultSet
.getInt(1);
961 } catch (SQLException e
) {
962 logger
.error("TaxonCount could not be determined: " + e
.getMessage());
970 * Checks whether a parent at specific level has a specific Rank.
971 * @param taxonName A {@link TaxonNameBase TaxonName}.
972 * @param level The ancestor level.
973 * @param ancestorRank The ancestor rank.
974 * @return Whether a parent at a specific level has a specific Rank.
976 private boolean validateAncestorOfSpecificRank(TaxonBase
<?
> taxonBase
, int level
, Rank ancestorRank
) {
977 boolean result
= false;
978 TaxonNode parentNode
= null;
979 if (taxonBase
.isInstanceOf(Taxon
.class)){
980 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
981 // Get ancestor Taxon via TaxonNode
982 Set
<TaxonNode
> taxonNodes
= taxon
.getTaxonNodes();
983 if (taxonNodes
.size() == 1) {
984 TaxonNode taxonNode
= taxonNodes
.iterator().next();
985 if (taxonNode
!= null) {
986 for (int i
= 0; i
< level
; i
++) {
987 if (taxonNode
!= null) {
988 taxonNode
= taxonNode
.getParent();
991 parentNode
= taxonNode
;
993 } else if (taxonNodes
.size() > 1) {
994 logger
.error("This taxon has " + taxonNodes
.size() + " taxonNodes: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
998 if (parentNode
!= null) {
999 TaxonNode node
= CdmBase
.deproxy(parentNode
, TaxonNode
.class);
1000 Taxon parentTaxon
= node
.getTaxon();
1001 if (parentTaxon
!= null) {
1002 TaxonName parentTaxonName
= parentTaxon
.getName();
1003 if (parentTaxonName
!= null && parentTaxonName
.getRank().equals(ancestorRank
)) {
1006 } else if (parentNode
.treeIndex().matches("#t\\d+#\\d+#")) {
1007 //do nothing (is root node)
1009 logger
.error("This TaxonNode has no Taxon: " + node
.getUuid());
1016 * Returns the AnnotationType for a given UUID.
1017 * @param uuid The Annotation UUID.
1018 * @param label The Annotation label.
1019 * @param text The Annotation text.
1020 * @param labelAbbrev The Annotation label abbreviation.
1021 * @return The AnnotationType.
1023 protected AnnotationType
getAnnotationType(UUID uuid
, String label
, String text
, String labelAbbrev
){
1024 AnnotationType annotationType
= (AnnotationType
)getTermService().find(uuid
);
1025 if (annotationType
== null) {
1026 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
1027 annotationType
.setUuid(uuid
);
1028 // annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1029 getTermService().save(annotationType
);
1031 return annotationType
;
1034 private boolean invokeParentTaxonFk(Integer parentId
, Integer childId
) {
1036 parentTaxonFkStmt
.setInt(1, parentId
);
1037 parentTaxonFkStmt
.setInt(2, childId
);
1038 parentTaxonFkStmt
.executeUpdate();
1040 } catch (SQLException e
) {
1041 logger
.warn("ParentTaxonFk (" + (parentId
==null?
"-":parentId
) + ") could not be inserted into database "
1042 + "for taxon "+ (childId
== null?
"-" :childId
) + ": " + e
.getMessage());
1043 e
.printStackTrace();
1050 * Inserts Rank data and KingdomFk into the Taxon database table.
1051 * @param taxonName The {@link TaxonNameBase TaxonName}.
1052 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1053 * @param taxonFk The TaxonFk to store the values for.
1055 * @param kindomFk The KingdomFk.
1056 * @return Whether save was successful or not.
1058 private boolean invokeRankDataAndKingdomFk(TaxonName taxonName
,
1059 Integer taxonFk
, Integer kingdomFk
, PesiExportState state
) {
1062 Integer rankFk
= getRankFk(taxonName
, kingdomFk
);
1063 if (rankFk
!= null) {
1064 rankUpdateStmt
.setInt(1, rankFk
);
1066 rankUpdateStmt
.setObject(1, null);
1069 String rankCache
= getRankCache(taxonName
, kingdomFk
, state
);
1070 if (rankCache
!= null) {
1071 rankUpdateStmt
.setString(2, rankCache
);
1073 rankUpdateStmt
.setObject(2, null);
1076 if (kingdomFk
!= null) {
1078 rankUpdateStmt
.setInt(3, kingdomFk
);
1080 rankUpdateStmt
.setObject(3, null);
1083 if (taxonFk
!= null) {
1084 rankUpdateStmt
.setInt(4, taxonFk
);
1086 rankUpdateStmt
.setObject(4, null);
1089 rankUpdateStmt
.executeUpdate();
1091 } catch (SQLException e
) {
1092 logger
.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e
.getMessage());
1093 e
.printStackTrace();
1099 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1100 * @param taxonName The {@link TaxonNameBase TaxonName}.
1101 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1102 * @param taxonFk The TaxonFk to store the values for.
1103 * @param typeNameFk The TypeNameFk.
1106 * @param kindomFk The KingdomFk.
1107 * @param expertFk The ExpertFk.
1108 * @param speciesExpertFk The SpeciesExpertFk.
1109 * @return Whether save was successful or not.
1111 private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonName taxonName
,
1112 Integer taxonFk
, Integer typeNameFk
, Integer kingdomFk
, Integer rankFk
, PesiExportState state
) {
1116 if (rankFk
!= null) {
1117 rankTypeExpertsUpdateStmt
.setInt(index
++, rankFk
);
1119 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1122 String rankCache
= getRankCache(taxonName
, kingdomFk
, state
);
1123 if (rankCache
!= null) {
1124 rankTypeExpertsUpdateStmt
.setString(index
++, rankCache
);
1126 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1129 if (typeNameFk
!= null) {
1130 rankTypeExpertsUpdateStmt
.setInt(index
++, typeNameFk
);
1132 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1135 if (kingdomFk
!= null) {
1136 rankTypeExpertsUpdateStmt
.setInt(index
++, kingdomFk
);
1138 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1141 // if (expertFk != null) {
1142 // rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1144 // rankTypeExpertsUpdateStmt.setObject(5, null);
1147 // //TODO handle experts GUIDS
1148 // if (speciesExpertFk != null) {
1149 // rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1151 // rankTypeExpertsUpdateStmt.setObject(6, null);
1154 if (taxonFk
!= null) {
1155 rankTypeExpertsUpdateStmt
.setInt(index
++, taxonFk
);
1157 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1160 rankTypeExpertsUpdateStmt
.executeUpdate();
1162 } catch (SQLException e
) {
1163 String name
= taxonName
== null?
null:taxonName
.getTitleCache();
1164 logger
.error("Data could not be inserted into database: " + e
.getMessage() + "; rankFk = " + rankFk
+ "; kingdomFk = " + kingdomFk
+ "; taxonFk = "+ taxonFk
+ "; typeNameFk = " + typeNameFk
+ "; name = " + name
);
1165 e
.printStackTrace();
1167 } catch (Exception e
) {
1168 String name
= taxonName
== null?
null:taxonName
.getTitleCache();
1169 logger
.error("Some exception occurred: " + e
.getMessage() + "; rankFk = " + rankFk
+ "; kingdomFk = " + kingdomFk
+ "; taxonFk = "+ taxonFk
+ "; typeNameFk = " + typeNameFk
+ "; name = " + name
);
1170 e
.printStackTrace();
1176 * Deletes all entries of database tables related to <code>Taxon</code>.
1177 * @param state The {@link PesiExportState PesiExportState}.
1178 * @return Whether the delete operation was successful or not.
1180 protected boolean doDelete(PesiExportState state
) {
1182 Source destination
= state
.getConfig().getDestination();
1184 String
[] tables
= new String
[]{"AdditionalTaxonSource","CommonNameSource","CommonName",
1185 "Image","NoteSource","Note","OccurrenceSource","Occurrence","RelTaxon","Taxon"};
1187 for(String table
: tables
){
1188 String sql
= "DELETE FROM " + table
;
1189 destination
.update(sql
);
1195 private static Integer
getRankFk(TaxonName taxonName
, NomenclaturalCode nomenclaturalCode
) {
1196 Integer kingdomId
= PesiTransformer
.nomenclaturalCode2Kingdom(nomenclaturalCode
);
1197 return getRankFk(taxonName
, kingdomId
);
1201 * Returns the <code>RankFk</code> attribute.
1202 * @param taxonName The {@link TaxonNameBase TaxonName}.
1203 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1204 * @return The <code>RankFk</code> attribute.
1207 private static Integer
getRankFk(TaxonName taxonName
, Integer kingdomId
) {
1208 Integer result
= null;
1210 if (taxonName
!= null) {
1211 if (taxonName
.getRank() == null) {
1212 logger
.warn("Rank is null: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1214 result
= PesiTransformer
.rank2RankId(taxonName
.getRank(), kingdomId
);
1216 if (result
== null) {
1217 logger
.warn("Rank could not be determined for PESI-Kingdom-Id " + kingdomId
+ " and TaxonName " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1220 } catch (Exception e
) {
1221 e
.printStackTrace();
1226 @SuppressWarnings("unused")
1227 private static String
getRankCache(TaxonName taxonName
, PesiExportState state
) {
1228 List
<TaxonNode
> nodes
= getTaxonNodes(taxonName
);
1230 if (nodes
== null||nodes
.isEmpty()){
1231 kingdomId
= getKingdomFk(taxonName
);
1233 //should not happen, method exists only pure names
1234 kingdomId
= findKingdomIdFromTreeIndex(nodes
.iterator().next().getTaxon(), state
);
1236 return getRankCache(taxonName
, kingdomId
, state
);
1239 private static String
getRankCache(TaxonName taxonName
, Integer kingdomFk
, PesiExportState state
) {
1240 if (Rank
.DOMAIN().equals(taxonName
.getRank())){
1241 return state
.getTransformer().getCacheByRankAndKingdom(Rank
.DOMAIN(), null);
1242 }else if (kingdomFk
!= null) {
1243 return state
.getTransformer().getCacheByRankAndKingdom(taxonName
.getRank(), kingdomFk
);
1244 }else if (taxonName
.getNameType() != null){
1245 return state
.getTransformer().getCacheByRankAndKingdom(taxonName
.getRank(), PesiTransformer
.nomenclaturalCode2Kingdom(taxonName
.getNameType()));
1247 logger
.warn("No kingdom ID could be defined for name " + taxonName
.getUuid());
1252 private static List
<TaxonNode
> getTaxonNodes(TaxonName taxonName
) {
1253 List
<TaxonNode
> result
= new ArrayList
<>();
1254 for (TaxonBase
<?
> tb
:taxonName
.getTaxonBases()){
1256 //TODO handle ERMS taxon relationships
1257 if (tb
.isInstanceOf(Taxon
.class)){
1258 taxon
= CdmBase
.deproxy(tb
, Taxon
.class);
1260 taxon
= CdmBase
.deproxy(tb
, Synonym
.class).getAcceptedTaxon();
1262 if (isPesiTaxon(taxon
)){
1263 for (TaxonNode node
: taxon
.getTaxonNodes()){
1271 // @SuppressWarnings("unused") //used by pure name mapper and by getRankFk
1272 private static Integer
getKingdomFk(TaxonName taxonName
){
1273 EnumSet
<PesiSource
> origin
= getSources(taxonName
);
1274 if (origin
.size() == 1 && origin
.contains(PesiSource
.EM
)){
1275 //maybe simply replace by
1276 //return PesiTransformer.KINGDOM_PLANTAE;
1277 return PesiTransformer
.nomenclaturalCode2Kingdom(taxonName
.getNameType());
1279 logger
.warn("getKingdomFk not yet implemented for non-EuroMed pure names");
1285 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1286 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1288 @SuppressWarnings("unused") //used by pure name mapper
1289 private static Integer
getRankFk(TaxonName taxonName
) {
1290 EnumSet
<PesiSource
> origin
= getSources(taxonName
);
1291 if (origin
.size() == 1 && origin
.contains(PesiSource
.EM
)){
1292 return getRankFk(taxonName
, getKingdomFk(taxonName
));
1294 logger
.warn("getRankFk not yet implemented for non-EuroMed pure names");
1300 * Returns the <code>DisplayName</code> attribute.
1301 * @param taxon The {@link TaxonBase Taxon}.
1302 * @return The <code>DisplayName</code> attribute.
1305 @SuppressWarnings("unused") //used by Mapper
1306 private static String
getDisplayName(TaxonBase
<?
> taxon
) {
1307 TaxonName taxonName
= taxon
.getName();
1308 String result
= getDisplayName(taxonName
);
1309 if (isMisappliedName(taxon
)){
1310 result
= result
+ " " + getAuthorString(taxon
);
1316 * Returns the <code>AuthorString</code> attribute.
1317 * @param taxonName The {@link TaxonNameBase TaxonName}.
1318 * @return The <code>AuthorString</code> attribute.
1322 protected static String
getAuthorString(TaxonBase
<?
> taxon
) {
1324 String result
= null;
1325 boolean isNonViralName
= false;
1326 String authorshipCache
= null;
1327 TaxonName taxonName
= taxon
.getName();
1328 if (taxonName
!= null && taxonName
.isNonViral()){
1329 authorshipCache
= taxonName
.getAuthorshipCache();
1330 isNonViralName
= true;
1332 result
= authorshipCache
;
1334 // For a misapplied names there are special rules
1335 if (isMisappliedName(taxon
)){
1336 if (taxon
.getSec() != null){
1337 String secTitle
= taxon
.getSec().getTitleCache();
1338 if (! secTitle
.startsWith("auct")){
1339 secTitle
= "sensu " + secTitle
;
1340 }else if (secTitle
.equals("auct")){ //may be removed once the title cache is generated correctly for references with title auct. #
1344 }else if (StringUtils
.isBlank(authorshipCache
)) {
1345 // Set authorshipCache to "auct."
1346 result
= PesiTransformer
.AUCT_STRING
;
1348 result
= PesiTransformer
.AUCT_STRING
;
1349 // result = authorshipCache;
1353 if (taxonName
== null){
1354 logger
.warn("TaxonName does not exist for taxon: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
1355 }else if (! isNonViralName
){
1356 logger
.warn("TaxonName is not of instance NonViralName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1359 if (StringUtils
.isBlank(result
)) {
1364 } catch (Exception e
) {
1365 e
.printStackTrace();
1371 * Returns the <code>DisplayName</code> attribute.
1372 * @param taxonName The {@link TaxonNameBase TaxonName}.
1373 * @return The <code>DisplayName</code> attribute.
1377 private static String
getDisplayName(TaxonName taxonName
) {
1379 if (taxonName
== null) {
1382 taxonName
= CdmBase
.deproxy(taxonName
);
1383 INonViralNameCacheStrategy cacheStrategy
= getCacheStrategy(taxonName
);
1384 HTMLTagRules tagRules
= new HTMLTagRules().
1385 addRule(TagEnum
.name
, "i").
1386 addRule(TagEnum
.nomStatus
, "@status@");
1389 if (getSources(taxonName
).contains(PesiSource
.ERMS
)){
1390 result
= cacheStrategy
.getTitleCache(taxonName
, tagRules
); //according to SQL script (also in ERMS sources are not abbreviated)
1391 }else if (getSources(taxonName
).contains(PesiSource
.EM
)){
1392 result
= cacheStrategy
.getFullTitleCache(taxonName
, tagRules
);
1394 //TODO define for FE + IF and for multiple sources
1395 result
= cacheStrategy
.getFullTitleCache(taxonName
, tagRules
);
1397 return result
.replaceAll("(, ?)?\\<@status@\\>.*\\</@status@\\>", "").trim();
1401 @SuppressWarnings("unused")
1402 private static String
getGUID(TaxonName taxonName
) {
1403 UUID uuid
= taxonName
.getUuid();
1404 String result
= "NameUUID:" + uuid
.toString();
1409 * Returns the <code>WebShowName</code> attribute for a taxon.
1410 * @param taxonName The {@link TaxonNameBase TaxonName}.
1411 * @return The <code>WebShowName</code> attribute.
1414 @SuppressWarnings("unused")
1415 private static String
getWebShowName(TaxonBase
<?
> taxon
) {
1416 TaxonName taxonName
= taxon
.getName();
1417 String result
= getWebShowName(taxonName
);
1418 if (isMisappliedName(taxon
)){
1419 result
= result
+ " " + getAuthorString(taxon
);
1425 * Returns the <code>WebShowName</code> attribute.
1426 * @param taxonName The {@link TaxonNameBase TaxonName}.
1427 * @return The <code>WebShowName</code> attribute.
1430 private static String
getWebShowName(TaxonName taxonName
) {
1432 if (taxonName
== null) {
1435 INonViralNameCacheStrategy cacheStrategy
= getCacheStrategy(taxonName
);
1437 HTMLTagRules tagRules
= new HTMLTagRules().addRule(TagEnum
.name
, "i");
1438 String result
= cacheStrategy
.getTitleCache(taxonName
, tagRules
);
1444 * Returns the <code>WebSearchName</code> attribute.
1445 * @param taxonName The {@link NonViralName NonViralName}.
1446 * @return The <code>WebSearchName</code> attribute.
1449 @SuppressWarnings("unused")
1450 private static String
getWebSearchName(TaxonName taxonName
) {
1452 TaxonNameDefaultCacheStrategy strategy
= getCacheStrategy(taxonName
);
1453 String result
= strategy
.getNameCache(taxonName
);
1458 * Returns the <code>FullName</code> attribute.
1459 * @param taxonName The {@link NonViralName NonViralName}.
1460 * @return The <code>FullName</code> attribute.
1463 @SuppressWarnings("unused")
1464 private static String
getFullName(TaxonName taxonName
) {
1466 String result
= getCacheStrategy(taxonName
).getTitleCache(taxonName
);
1467 Iterator
<Taxon
> taxa
= taxonName
.getTaxa().iterator();
1468 if (taxonName
.getTaxa().size() >0){
1469 if (taxonName
.getTaxa().size() == 1){
1470 Taxon taxon
= taxa
.next();
1471 if (isMisappliedName(taxon
)){
1472 result
= result
+ " " + getAuthorString(taxon
);
1481 * Returns the SourceNameCache for the AdditionalSource table
1485 static boolean isFirstAbbrevTitle
= true;
1486 @SuppressWarnings("unused")
1487 private static String
getSourceNameCache(TaxonName taxonName
) {
1488 if (taxonName
!= null){
1489 Reference nomRef
= taxonName
.getNomenclaturalReference();
1490 if (nomRef
!= null ){
1491 if (isFirstAbbrevTitle
){
1492 //#5388 is definetely not the correct ticket number
1493 logger
.warn("Semantics of getAbbrevTitleCache has changed. Please check if output is still correct. See #5388");
1494 isFirstAbbrevTitle
= false;
1496 return nomRef
.getAbbrevTitleCache();
1503 * Returns the nomenclatural reference which is the reference
1504 * including the detail (microreference).
1505 * @param taxonName The {@link TaxonName taxon name}.
1508 @SuppressWarnings("unused")
1509 private static String
getNomRefString(TaxonName taxonName
) {
1510 INomenclaturalReference ref
= taxonName
.getNomenclaturalReference();
1514 String result
= null;
1515 EnumSet
<PesiSource
> sources
= getSources(taxonName
);
1516 if(sources
.contains(PesiSource
.EM
)){
1517 if (! ref
.isProtectedAbbrevTitleCache()){
1518 ref
.setAbbrevTitleCache(null, false); //to remove a false cache
1520 result
= ref
.getNomenclaturalCitation(taxonName
.getNomenclaturalMicroReference());
1521 }else if(sources
.contains(PesiSource
.FE
)||sources
.contains(PesiSource
.IF
) ){
1522 //TODO still need to check if correct for FE + IF
1523 if (! ref
.isProtectedAbbrevTitleCache()){
1524 ref
.setAbbrevTitleCache(null, false); //to remove a false cache
1526 result
= ref
.getNomenclaturalCitation(taxonName
.getNomenclaturalMicroReference());
1527 return result
; // according to SQL script
1528 }else if(sources
.contains(PesiSource
.ERMS
)) {
1529 //result = null; //according to SQL script
1531 logger
.warn("Source not yet supported");
1537 * Returns the <code>NameStatusFk</code> attribute.
1538 * @param taxonName The {@link TaxonNameBase TaxonName}.
1539 * @return The <code>NameStatusFk</code> attribute.
1542 @SuppressWarnings("unused")
1543 private static Integer
getNameStatusFk(TaxonName taxonName
) {
1544 Integer result
= null;
1546 NomenclaturalStatus status
= getNameStatus(taxonName
);
1547 if (status
!= null) {
1548 result
= PesiTransformer
.nomStatus2nomStatusFk(status
.getType());
1554 * Returns the <code>NameStatusCache</code> attribute.
1555 * @param taxonName The {@link TaxonNameBase TaxonName}.
1556 * @return The <code>NameStatusCache</code> attribute.
1557 * @throws UndefinedTransformerMethodException
1560 @SuppressWarnings("unused")
1561 private static String
getNameStatusCache(TaxonName taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1562 String result
= null;
1563 NomenclaturalStatus status
= getNameStatus(taxonName
);
1564 if (status
!= null) {
1565 result
= state
.getTransformer().getCacheByNomStatus(status
.getType());
1570 private static NomenclaturalStatus
getNameStatus(TaxonName taxonName
) {
1572 if (taxonName
!= null) {
1573 Set
<NomenclaturalStatus
> states
= taxonName
.getStatus();
1574 if (states
.size() == 1) {
1575 NomenclaturalStatus status
= states
.iterator().next();
1577 } else if (states
.size() > 1) {
1578 logger
.error("This TaxonName has more than one Nomenclatural Status: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1581 } catch (Exception e
) {
1582 e
.printStackTrace();
1587 * Returns the <code>TaxonStatusFk</code> attribute.
1588 * @param taxonName The {@link TaxonNameBase TaxonName}.
1589 * @param state The {@link PesiExportState PesiExportState}.
1590 * @return The <code>TaxonStatusFk</code> attribute.
1593 private static Integer
getTaxonStatusFk(TaxonBase
<?
> taxon
, PesiExportState state
) {
1594 Integer result
= null;
1597 // if (isMisappliedName(taxon)) {
1598 // Synonym synonym = Synonym.NewInstance(null, null);
1600 // // This works as long as only the instance is important to differentiate between TaxonStatus.
1601 // result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in datawarehouse now.
1603 //this should work now, the method itself distinguishes MAN etc.
1604 result
= PesiTransformer
.taxonBase2statusFk(taxon
);
1606 } catch (Exception e
) {
1607 e
.printStackTrace();
1613 * Returns the <code>TaxonStatusCache</code> attribute.
1614 * @param taxonName The {@link TaxonNameBase TaxonName}.
1615 * @param state The {@link PesiExportState PesiExportState}.
1616 * @return The <code>TaxonStatusCache</code> attribute.
1617 * @throws UndefinedTransformerMethodException
1620 @SuppressWarnings("unused")
1621 private static String
getTaxonStatusCache(TaxonBase
<?
> taxon
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1622 return state
.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon
, state
));
1626 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
1627 * @param relationship The {@link RelationshipBase Relationship}.
1628 * @param state The {@link PesiExportState PesiExportState}.
1629 * @return The <code>TaxonFk1</code> attribute.
1632 @SuppressWarnings("unused")
1633 private static Integer
getSynonym(Synonym synonym
, PesiExportState state
) {
1634 return state
.getDbId(synonym
);
1638 * Returns the <code>TypeNameFk</code> attribute.
1639 * @param taxonName The {@link TaxonNameBase TaxonName}.
1640 * @param state The {@link PesiExportState PesiExportState}.
1641 * @return The <code>TypeNameFk</code> attribute.
1644 private static Integer
getTypeNameFk(TaxonName taxonName
, PesiExportState state
) {
1645 Integer result
= null;
1646 if (taxonName
!= null) {
1647 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonName
.getNameTypeDesignations();
1648 if (nameTypeDesignations
.size() == 1) {
1649 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1650 if (nameTypeDesignation
!= null) {
1651 TaxonName typeName
= nameTypeDesignation
.getTypeName();
1652 if (typeName
!= null) {
1653 if (typeName
.getTaxonBases().isEmpty()){
1654 logger
.warn("type name does not belong to a taxon and therefore is expected to not be a European taxon. Type name not added. Type name: " + typeName
.getTitleCache() + ", typified name: " + taxonName
.getTitleCache());
1656 result
= state
.getDbId(typeName
);
1660 } else if (nameTypeDesignations
.size() > 1) {
1661 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1668 * Returns the <code>TypeFullnameCache</code> attribute.
1669 * @param taxonName The {@link TaxonNameBase TaxonName}.
1670 * @return The <code>TypeFullnameCache</code> attribute.
1673 @SuppressWarnings("unused")
1674 private static String
getTypeFullnameCache(TaxonName taxonName
) {
1675 String result
= null;
1678 if (taxonName
!= null) {
1679 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonName
.getNameTypeDesignations();
1680 if (nameTypeDesignations
.size() == 1) {
1681 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1682 if (nameTypeDesignation
!= null) {
1683 TaxonName typeName
= nameTypeDesignation
.getTypeName();
1684 if (typeName
!= null) {
1685 result
= typeName
.getTitleCache();
1688 } else if (nameTypeDesignations
.size() > 1) {
1689 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1692 } catch (Exception e
) {
1693 e
.printStackTrace();
1700 * Returns the <code>QualityStatusFk</code> attribute.
1701 * @param taxonName The {@link TaxonNameBase TaxonName}.
1702 * @return The <code>QualityStatusFk</code> attribute.
1705 private static Integer
getQualityStatusFk(TaxonName taxonName
) {
1706 EnumSet
<PesiSource
> sources
= getSources(taxonName
);
1707 return PesiTransformer
.getQualityStatusKeyBySource(sources
, taxonName
);
1711 * Returns the <code>QualityStatusCache</code> attribute.
1712 * @param taxonName The {@link TaxonNameBase TaxonName}.
1713 * @return The <code>QualityStatusCache</code> attribute.
1714 * @throws UndefinedTransformerMethodException
1717 @SuppressWarnings("unused")
1718 private static String
getQualityStatusCache(TaxonName taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1719 return state
.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName
));
1724 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1725 * @param taxonName The {@link TaxonNameBase TaxonName}.
1726 * @return The <code>TypeDesignationStatusFk</code> attribute.
1729 //TODO seems not to be used
1730 private static Integer
getTypeDesignationStatusFk(TaxonName taxonName
) {
1731 Integer result
= null;
1734 if (taxonName
!= null) {
1735 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1736 if (typeDesignations
.size() == 1) {
1737 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1738 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1739 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus
);
1740 } else if (typeDesignations
.size() > 1) {
1741 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1744 } catch (Exception e
) {
1745 e
.printStackTrace();
1751 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1752 * @param taxonName The {@link TaxonNameBase TaxonName}.
1753 * @return The <code>TypeDesignationStatusCache</code> attribute.
1756 //TODO seems not to be used
1757 private static String
getTypeDesignationStatusCache(TaxonName taxonName
) {
1758 String result
= null;
1761 if (taxonName
!= null) {
1762 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1763 if (typeDesignations
.size() == 1) {
1764 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1765 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1766 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus
);
1767 } else if (typeDesignations
.size() > 1) {
1768 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1771 } catch (Exception e
) {
1772 e
.printStackTrace();
1778 * Returns the <code>FossilStatusFk</code> attribute.
1779 * @param taxonName The {@link TaxonNameBase TaxonName}.
1780 * @return The <code>FossilStatusFk</code> attribute.
1783 @SuppressWarnings("unused")
1784 private static Integer
getFossilStatusFk(IdentifiableEntity
<?
> identEntity
, PesiExportState state
) {
1785 Integer result
= null;
1787 Set
<String
> fossilStatuus
= identEntity
.getExtensions(ErmsTransformer
.uuidExtFossilStatus
);
1788 if (fossilStatuus
.size() == 0){
1790 }else if (fossilStatuus
.size() > 1){
1791 logger
.warn("More than 1 fossil status given for " + identEntity
.getTitleCache() + " " + identEntity
.getUuid());
1793 String fossilStatus
= fossilStatuus
.iterator().next();
1795 int statusFk
= state
.getTransformer().fossilStatusCache2FossilStatusFk(fossilStatus
);
1800 * Returns the <code>FossilStatusCache</code> attribute.
1801 * @param taxonName The {@link TaxonNameBase TaxonName}.
1802 * @return The <code>FossilStatusCache</code> attribute.
1805 @SuppressWarnings("unused")
1806 private static String
getFossilStatusCache(IdentifiableEntity
<?
> identEntity
, PesiExportState state
) {
1807 String result
= null;
1808 Set
<String
> fossilStatuus
= identEntity
.getExtensions(ErmsTransformer
.uuidExtFossilStatus
);
1809 if (fossilStatuus
.size() == 0){
1812 for (String strFossilStatus
: fossilStatuus
){
1813 result
= CdmUtils
.concat(";", result
, strFossilStatus
);
1819 * Returns the <code>IdInSource</code> attribute.
1820 * @param taxonName The {@link TaxonNameBase TaxonName}.
1821 * @return The <code>IdInSource</code> attribute.
1824 @SuppressWarnings("unused")
1825 private static String
getIdInSource(IdentifiableEntity
<?
> taxonName
) {
1826 String result
= null;
1829 Set
<IdentifiableSource
> sources
= getPesiSources(taxonName
);
1830 if (sources
.size() > 1){
1831 logger
.warn("There is > 1 Pesi source. This is not yet handled.");
1833 if (sources
.size() == 0){
1834 logger
.warn("There is no Pesi source!" +taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
1836 for (IdentifiableSource source
: sources
) {
1837 Reference ref
= source
.getCitation();
1838 UUID refUuid
= ref
.getUuid();
1839 String idInSource
= source
.getIdInSource();
1840 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
1841 result
= idInSource
!= null ?
("NameId: " + source
.getIdInSource()) : null;
1842 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
1843 result
= idInSource
!= null ?
("TAX_ID: " + source
.getIdInSource()) : null;
1844 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
1845 result
= idInSource
!= null ?
("tu_id: " + source
.getIdInSource()) : null;
1846 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){ //Index Fungorum
1847 result
= idInSource
!= null ?
("if_id: " + source
.getIdInSource()) : null;
1849 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");}
1852 String sourceIdNameSpace
= source
.getIdNamespace();
1853 if (sourceIdNameSpace
!= null) {
1854 if (sourceIdNameSpace
.equals(PesiTransformer
.STR_NAMESPACE_NOMINAL_TAXON
)) {
1855 result
= idInSource
!= null ?
("Nominal Taxon from TAX_ID: " + source
.getIdInSource()):null;
1856 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_EPITHET_NAMESPACE
)) {
1857 result
= idInSource
!= null ?
("Inferred epithet from TAX_ID: " + source
.getIdInSource()) : null;
1858 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_GENUS_NAMESPACE
)) {
1859 result
= idInSource
!= null ?
("Inferred genus from TAX_ID: " + source
.getIdInSource()):null;
1860 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.POTENTIAL_COMBINATION_NAMESPACE
)) {
1861 result
= idInSource
!= null ?
("Potential combination from TAX_ID: " + source
.getIdInSource()):null;
1864 if (result
== null) {
1865 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +", sourceIdNameSpace: " + source
.getIdNamespace()+")");
1868 } catch (Exception e
) {
1869 e
.printStackTrace();
1870 logger
.error("An error occurs while creating idInSource..." + taxonName
.getUuid() + " (" + taxonName
.getTitleCache()+ e
.getMessage());
1873 if (result
== null) {
1874 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
1880 * Returns the idInSource for a given TaxonName only.
1881 * @param taxonName The {@link TaxonNameBase TaxonName}.
1882 * @return The idInSource.
1884 private static String
getIdInSourceOnly(IdentifiableEntity
<?
> identEntity
) {
1885 String result
= null;
1887 // Get the sources first
1888 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
1890 // Determine the idInSource
1891 if (sources
.size() == 1) {
1892 IdentifiableSource source
= sources
.iterator().next();
1893 if (source
!= null) {
1894 result
= source
.getIdInSource();
1896 } else if (sources
.size() > 1) {
1899 for (IdentifiableSource source
: sources
) {
1900 result
+= source
.getIdInSource();
1901 if (count
< sources
.size()) {
1913 * Returns the <code>GUID</code> attribute.
1914 * @param taxonName The {@link TaxonNameBase TaxonName}.
1915 * @return The <code>GUID</code> attribute.
1918 private static String
getGUID(TaxonBase
<?
> taxon
) {
1919 if (taxon
.getLsid() != null ){
1920 return taxon
.getLsid().getLsid();
1921 }else if (taxon
.hasMarker(PesiTransformer
.uuidMarkerGuidIsMissing
, true)){
1924 return taxon
.getUuid().toString();
1929 * Returns the <code>DerivedFromGuid</code> attribute.
1930 * @param taxonName The {@link TaxonNameBase TaxonName}.
1931 * @return The <code>DerivedFromGuid</code> attribute.
1934 @SuppressWarnings("unused")
1935 private static String
getDerivedFromGuid(TaxonBase
<?
> taxon
) {
1936 String result
= null;
1938 // The same as GUID for now
1939 result
= getGUID(taxon
);
1940 } catch (Exception e
) {
1941 e
.printStackTrace();
1947 * Returns the <code>CacheCitation</code> attribute.
1948 * @param taxonName The {@link TaxonNameBase TaxonName}.
1949 * @return The CacheCitation.
1952 @SuppressWarnings("unused")
1953 private static String
getCacheCitation(TaxonBase
<?
> taxon
) {
1954 // !!! See also doPhaseUpdates
1956 TaxonName taxonName
= taxon
.getName();
1958 //TODO implement anew for taxa
1960 EnumSet
<PesiSource
> sources
= getSources(taxon
);
1961 if (sources
.isEmpty()) {
1962 // logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1963 } else if (sources
.contains(PesiSource
.ERMS
)) {
1964 Set
<Extension
> extensions
= taxon
.getExtensions();
1965 for (Extension extension
: extensions
) {
1966 if (extension
.getType().equals(cacheCitationExtensionType
)) {
1967 result
= extension
.getValue();
1971 String expertName
= getExpertName(taxon
);
1972 String webShowName
= getWebShowName(taxonName
);
1975 String idInSource
= getIdInSourceOnly(taxonName
);
1977 // build the cacheCitation
1978 if (expertName
!= null) {
1979 result
+= expertName
+ ". ";
1981 if (logger
.isDebugEnabled()){logger
.debug("ExpertName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");}
1983 if (webShowName
!= null) {
1984 result
+= webShowName
+ ". ";
1986 logger
.warn("WebShowName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1989 if (getOriginalDB(taxonName
).equals("FaEu")) {
1990 result
+= "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
1991 } else if (getOriginalDB(taxonName
).equals("EM")) {
1992 result
+= "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
1995 if (idInSource
!= null) {
1996 result
+= idInSource
;
1998 logger
.warn("IdInSource could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
2001 } catch (Exception e
) {
2002 e
.printStackTrace();
2005 if (StringUtils
.isBlank(result
)) {
2013 * Returns the <code>OriginalDB</code> attribute.
2014 * @param identifiableEntity
2015 * @return The <code>OriginalDB</code> attribute.
2018 // @SuppressWarnings("unused")
2019 private static String
getOriginalDB(IdentifiableEntity
<?
> identifiableEntity
) {
2020 EnumSet
<PesiSource
> sources
= getSources(identifiableEntity
);
2021 return PesiTransformer
.getOriginalDbBySources(sources
);
2025 * Returns the <code>ExpertName</code> attribute.
2026 * @param taxonName The {@link TaxonNameBase TaxonName}.
2027 * @return The <code>ExpertName</code> attribute.
2030 @SuppressWarnings("unused") //for some reason it is also called by getCacheCitation
2031 private static String
getExpertName(TaxonBase
<?
> taxon
) {
2033 String result
= null;
2034 if(expertNameExtensionType
!=null){ //some databases do not have this extension type
2035 Set
<Extension
> extensions
= taxon
.getExtensions();
2036 for (Extension extension
: extensions
) {
2037 if (extension
.getType().equals(expertNameExtensionType
)) {
2038 result
= extension
.getValue();
2042 if (getPesiSources(taxon
).contains(PesiSource
.EM
)){
2043 return taxon
.getSec().getTitleCache();
2046 } catch (Exception e
) {
2047 e
.printStackTrace();
2052 //TODO change to ExpertGUID
2053 private static Integer
getExpertFk(Reference reference
, PesiExportState state
) {
2054 Integer result
= state
.getDbId(reference
);
2059 * Returns the <code>SpeciesExpertName</code> attribute.
2060 * @param taxonName The {@link TaxonNameBase TaxonName}.
2061 * @return The <code>SpeciesExpertName</code> attribute.
2064 @SuppressWarnings("unused")
2065 private static String
getSpeciesExpertName(TaxonBase
<?
> taxon
) {
2067 Set
<Extension
> extensions
= taxon
.getExtensions();
2068 if(speciesExpertNameExtensionType
!=null){ //some databases do not have this extension type
2069 for (Extension extension
: extensions
) {
2070 if (extension
.getType().equals(speciesExpertNameExtensionType
)) {
2071 return extension
.getValue();
2075 if (getPesiSources(taxon
).contains(PesiSource
.EM
)){
2076 return taxon
.getSec().getTitleCache();
2079 } catch (Exception e
) {
2080 e
.printStackTrace();
2086 * Returns the <code>SpeciesExpertFk</code> attribute.
2087 * @param reference The {@link Reference Reference}.
2088 * @param state The {@link PesiExportState PesiExportState}.
2089 * @return The <code>SpeciesExpertFk</code> attribute.
2092 //TODO should be changed to SpeciesExpertGUID
2093 private static Integer
getSpeciesExpertFk(Reference reference
, PesiExportState state
) {
2094 Integer result
= state
.getDbId(reference
);
2098 protected static TaxonNameDefaultCacheStrategy
getCacheStrategy(TaxonName taxonName
) {
2099 taxonName
= CdmBase
.deproxy(taxonName
);
2100 TaxonNameDefaultCacheStrategy cacheStrategy
;
2101 if (taxonName
.isZoological()){
2102 cacheStrategy
= zooNameStrategy
;
2103 }else if (taxonName
.isBotanical()) {
2104 cacheStrategy
= nonViralNameStrategy
;
2105 }else if (taxonName
.isNonViral()) {
2106 cacheStrategy
= nonViralNameStrategy
;
2107 }else if (taxonName
.isBacterial()) {
2108 cacheStrategy
= nonViralNameStrategy
;
2110 logger
.error("Unhandled taxon name type. Can't define strategy class");
2111 cacheStrategy
= nonViralNameStrategy
;
2113 return cacheStrategy
;
2117 * Returns the <code>RelTaxonQualifierFk</code> attribute.
2118 * @param relationship The {@link RelationshipBase Relationship}.
2119 * @return The <code>RelTaxonQualifierFk</code> attribute.
2122 @SuppressWarnings("unused")
2123 private static Integer
getRelTaxonQualifierFk(RelationshipBase
<?
, ?
, ?
> relationship
) {
2124 return PesiTransformer
.taxonRelation2RelTaxonQualifierFk(relationship
);
2127 //TODO still in use?
2128 private static String
getSynonymTypeCache(Synonym synonym
, PesiExportState state
) {
2129 String result
= null;
2130 NomenclaturalCode code
= null;
2131 code
= CdmBase
.deproxy(synonym
, Synonym
.class).getAcceptedTaxon().getName().getNameType();
2134 result
= state
.getConfig().getTransformer().getCacheBySynonymType(synonym
, code
);
2136 logger
.error("NomenclaturalCode is NULL while creating the following synonym: " + synonym
.getUuid());
2141 // ********************************** MAPPINGS ********************************/
2144 * Returns the CDM to PESI specific export mappings.
2145 * @return The {@link PesiExportMapping PesiExportMapping}.
2147 private PesiExportMapping
getMapping() {
2148 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2150 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2151 mapping
.addMapper(DbObjectMapper
.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2152 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter
, PesiExportState
.class));
2153 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter
, PesiExportState
.class));
2155 mapping
.addMapper(MethodMapper
.NewInstance("GUID", this));
2157 mapping
.addMapper(MethodMapper
.NewInstance("DerivedFromGuid", this));
2158 mapping
.addMapper(MethodMapper
.NewInstance("CacheCitation", this));
2159 mapping
.addMapper(MethodMapper
.NewInstance("AuthorString", this)); //For Taxon because Misapllied Names are handled differently
2160 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this));
2163 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this));
2165 // FossilStatus (Fk, Cache)
2166 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusCache", this, IdentifiableEntity
.class, PesiExportState
.class));
2167 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusFk", this, IdentifiableEntity
.class, PesiExportState
.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2169 //handled by name mapping
2170 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2171 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2174 // mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));
2175 mapping
.addMapper(MethodMapper
.NewInstance("SpeciesExpertName", this, TaxonBase
.class));
2176 // ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.uuidExtExpertName);
2177 // mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));
2178 mapping
.addMapper(MethodMapper
.NewInstance("ExpertName", this, TaxonBase
.class));
2180 //ParentTaxonFk handled in Phase02 now
2181 mapping
.addMapper(ObjectChangeMapper
.NewInstance(TaxonBase
.class, TaxonName
.class, "Name"));
2183 addNameMappers(mapping
);
2189 * Returns the CDM to PESI specific export mappings.
2191 * @return The {@link PesiExportMapping PesiExportMapping}.
2192 * @throws UndefinedTransformerMethodException
2194 private PesiExportMapping
getPureNameMapping(PesiExportState state
) throws UndefinedTransformerMethodException
{
2195 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2197 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2199 mapping
.addMapper(MethodMapper
.NewInstance("KingdomFk", this, TaxonName
.class));
2200 mapping
.addMapper(MethodMapper
.NewInstance("RankFk", this, TaxonName
.class));
2201 mapping
.addMapper(MethodMapper
.NewInstance("RankCache", this, TaxonName
.class, PesiExportState
.class));
2202 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusFk", Types
.INTEGER
, PesiTransformer
.T_STATUS_UNACCEPTED
));
2203 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusCache", Types
.VARCHAR
, state
.getTransformer().getTaxonStatusCacheByKey( PesiTransformer
.T_STATUS_UNACCEPTED
)));
2204 mapping
.addMapper(DbStringMapper
.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
2205 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this, TaxonName
.class));
2206 mapping
.addMapper(MethodMapper
.NewInstance("GUID", this, TaxonName
.class));
2209 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this, TaxonName
.class));
2211 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2212 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2214 addNameMappers(mapping
);
2218 private void addNameMappers(PesiExportMapping mapping
) {
2221 mapping
.addMapper(DbStringMapper
.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2222 mapping
.addMapper(DbStringMapper
.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2223 mapping
.addMapper(DbStringMapper
.NewInstance("SpecificEpithet", "SpecificEpithet"));
2224 mapping
.addMapper(DbStringMapper
.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2227 // mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName")); //does not work as we need other cache strategy
2228 mapping
.addMapper(MethodMapper
.NewInstance("WebSearchName", this, TaxonName
.class));
2229 mapping
.addMapper(MethodMapper
.NewInstance("FullName", this, TaxonName
.class));
2232 mapping
.addMapper(MethodMapper
.NewInstance("NomRefString", this, TaxonName
.class));
2235 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusFk", this, TaxonName
.class));
2236 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusCache", this, TaxonName
.class, PesiExportState
.class));
2237 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusFk", this, TaxonName
.class));
2238 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusCache", this, TaxonName
.class, PesiExportState
.class));
2241 mapping
.addMapper(MethodMapper
.NewInstance("TypeFullnameCache", this, TaxonName
.class));
2242 //TypeNameFk handled in Phase3
2245 mapping
.addMapper(MethodMapper
.NewInstance("IdInSource", this, IdentifiableEntity
.class));
2246 mapping
.addMapper(MethodMapper
.NewInstance("OriginalDB", this, IdentifiableEntity
.class) );
2248 //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2252 private PesiExportMapping
getSynRelMapping() {
2253 PesiExportMapping mapping
= new PesiExportMapping(dbTableNameSynRel
);
2254 logger
.warn("SynRelMapping currently not implemented. Needs to be checked");
2256 mapping
.addMapper(MethodMapper
.NewInstance("TaxonFk1", this.getClass(), "getSynonym", Synonym
.class, PesiExportState
.class));
2257 mapping
.addMapper(DbObjectMapper
.NewInstance("acceptedTaxon", "TaxonFk2"));
2258 mapping
.addMapper(DbObjectMapper
.NewInstance("type", "RelTaxonQualifierFk"));
2259 mapping
.addMapper(MethodMapper
.NewInstance("RelQualifierCache", this.getClass(), "getSynonymTypeCache", Synonym
.class, PesiExportState
.class));
2261 // mapping.addMapper(MethodMapper.NewInstance("Notes", this, RelationshipBase.class));
2266 private PesiExportMapping
getAdditionalSourceMapping(PesiExportState state
) {
2267 PesiExportMapping mapping
= new PesiExportMapping(dbTableAdditionalSourceRel
);
2269 mapping
.addMapper(IdMapper
.NewInstance("TaxonFk"));
2270 mapping
.addMapper(ObjectChangeMapper
.NewInstance(TaxonBase
.class, TaxonName
.class, "Name"));
2272 mapping
.addMapper(DbObjectMapper
.NewInstance("NomenclaturalReference", "SourceFk"));
2273 // mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE));
2274 mapping
.addMapper(MethodMapper
.NewInstance("SourceNameCache", this, TaxonName
.class));
2276 //we have only nomenclatural references here
2277 mapping
.addMapper(DbConstantMapper
.NewInstance("SourceUseFk", Types
.INTEGER
, PesiTransformer
.NOMENCLATURAL_REFERENCE
));
2278 mapping
.addMapper(DbConstantMapper
.NewInstance("SourceUseCache", Types
.VARCHAR
, state
.getTransformer().getSourceUseCacheByKey( PesiTransformer
.NOMENCLATURAL_REFERENCE
)));
2280 mapping
.addMapper(DbStringMapper
.NewInstance("NomenclaturalMicroReference", "SourceDetail"));
2287 protected boolean doCheck(PesiExportState state
) {
2292 protected boolean isIgnore(PesiExportState state
) {
2293 return ! state
.getConfig().isDoTaxa();