3 * Copyright (C) 2009 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.io
.pesi
.out
;
12 import java
.sql
.Connection
;
13 import java
.sql
.PreparedStatement
;
14 import java
.sql
.ResultSet
;
15 import java
.sql
.SQLException
;
16 import java
.sql
.Types
;
17 import java
.util
.ArrayList
;
18 import java
.util
.BitSet
;
19 import java
.util
.HashMap
;
20 import java
.util
.HashSet
;
21 import java
.util
.Iterator
;
22 import java
.util
.List
;
24 import java
.util
.UUID
;
26 import org
.apache
.commons
.lang
.StringUtils
;
27 import org
.apache
.log4j
.Logger
;
28 import org
.joda
.time
.DateTime
;
29 import org
.joda
.time
.format
.DateTimeFormat
;
30 import org
.joda
.time
.format
.DateTimeFormatter
;
31 import org
.springframework
.stereotype
.Component
;
32 import org
.springframework
.transaction
.TransactionStatus
;
34 import eu
.etaxonomy
.cdm
.api
.service
.TaxonServiceImpl
;
35 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
36 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
37 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
38 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbConstantMapper
;
39 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbExtensionMapper
;
40 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbLastActionMapper
;
41 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbObjectMapper
;
42 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbStringMapper
;
43 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.IdMapper
;
44 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.MethodMapper
;
45 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.ObjectChangeMapper
;
46 import eu
.etaxonomy
.cdm
.io
.pesi
.erms
.ErmsTransformer
;
47 import eu
.etaxonomy
.cdm
.io
.profiler
.ProfilerController
;
48 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
49 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
50 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
51 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
52 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
53 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
54 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
55 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
56 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
57 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
58 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
59 import eu
.etaxonomy
.cdm
.model
.name
.BacterialName
;
60 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
61 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
62 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
63 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
64 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignationStatus
;
65 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
66 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
67 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
68 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
69 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
70 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
71 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
72 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
73 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
74 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
81 import eu
.etaxonomy
.cdm
.strategy
.cache
.HTMLTagRules
;
82 import eu
.etaxonomy
.cdm
.strategy
.cache
.TagEnum
;
83 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.BacterialNameDefaultCacheStrategy
;
84 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.BotanicNameDefaultCacheStrategy
;
85 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INonViralNameCacheStrategy
;
86 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.NonViralNameDefaultCacheStrategy
;
87 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.ZooNameNoMarkerCacheStrategy
;
90 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
91 * Inserts into DataWarehouse database table <code>Taxon</code>.
92 * It is divided into four phases:<p><ul>
93 * <li>Phase 1: Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.
94 * <li>Phase 2: Export of additional data: ParenTaxonFk and TreeIndex.
95 * <li>Phase 3: Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
96 * <li>Phase 4: Export of Inferred Synonyms.</ul>
102 public class PesiTaxonExport
extends PesiExportBase
{
103 private static final Logger logger
= Logger
.getLogger(PesiTaxonExport
.class);
104 private static final Class
<?
extends CdmBase
> standardMethodParameter
= TaxonBase
.class;
106 private static int modCount
= 1000;
107 private static final String dbTableName
= "Taxon";
108 private static final String dbTableNameSynRel
= "RelTaxon";
109 private static final String dbTableAdditionalSourceRel
= "AdditionalTaxonSource";
110 private static final String pluralString
= "Taxa";
111 private static final String parentPluralString
= "Taxa";
112 private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt
;
113 private PreparedStatement parentTaxonFkStmt
;
114 private PreparedStatement rankTypeExpertsUpdateStmt
;
115 private PreparedStatement rankUpdateStmt
;
116 private NomenclaturalCode nomenclaturalCode
;
117 private Integer kingdomFk
;
118 private HashMap
<Rank
, Rank
> rank2endRankMap
= new HashMap
<Rank
, Rank
>();
119 private List
<Rank
> rankList
= new ArrayList
<Rank
>();
120 private static final UUID uuidTreeIndex
= UUID
.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");
121 private AnnotationType treeIndexAnnotationType
;
122 private static ExtensionType lastActionExtensionType
;
123 private static ExtensionType lastActionDateExtensionType
;
124 private static ExtensionType expertNameExtensionType
;
125 private static ExtensionType speciesExpertNameExtensionType
;
126 private static ExtensionType cacheCitationExtensionType
;
127 public static NonViralNameDefaultCacheStrategy
<?
> zooNameStrategy
= ZooNameNoMarkerCacheStrategy
.NewInstance();
128 public static NonViralNameDefaultCacheStrategy
<?
> botanicalNameStrategy
= BotanicNameDefaultCacheStrategy
.NewInstance();
129 public static NonViralNameDefaultCacheStrategy
<?
> nonViralNameStrategy
= NonViralNameDefaultCacheStrategy
.NewInstance();
130 public static NonViralNameDefaultCacheStrategy
<?
> bacterialNameStrategy
= BacterialNameDefaultCacheStrategy
.NewInstance();
131 private static int currentTaxonId
;
135 * @return the treeIndexAnnotationType
137 protected AnnotationType
getTreeIndexAnnotationType() {
138 return treeIndexAnnotationType
;
142 * @param treeIndexAnnotationType the treeIndexAnnotationType to set
144 protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType
) {
145 this.treeIndexAnnotationType
= treeIndexAnnotationType
;
156 public PesiTaxonExport() {
161 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
164 public Class
<?
extends CdmBase
> getStandardMethodParameter() {
165 return standardMethodParameter
;
169 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
172 protected boolean doCheck(PesiExportState state
) {
173 boolean result
= true;
179 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
182 protected void doInvoke(PesiExportState state
) {
184 logger
.info("*** Started Making " + pluralString
+ " ...");
186 initPreparedStatements(state
);
188 // Stores whether this invoke was successful or not.
189 boolean success
= true;
191 // PESI: Clear the database table Taxon.
194 // Get specific mappings: (CDM) Taxon -> (PESI) Taxon
195 PesiExportMapping mapping
= getMapping();
196 PesiExportMapping synonymRelMapping
= getSynRelMapping();
197 PesiExportMapping additionalSourceMapping
= getAdditionalSourceMapping(state
);
199 // Initialize the db mapper
200 mapping
.initialize(state
);
201 synonymRelMapping
.initialize(state
);
202 additionalSourceMapping
.initialize(state
);
204 // Find extensionTypes
205 lastActionExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.lastActionUuid
);
206 lastActionDateExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.lastActionDateUuid
);
207 expertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.expertNameUuid
);
208 speciesExpertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.speciesExpertNameUuid
);
209 cacheCitationExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.cacheCitationUuid
);
212 success
&= doPhase01(state
, mapping
, additionalSourceMapping
);
214 //"PHASE 1b: Handle names without taxa ...
215 success
&= doNames(state
, additionalSourceMapping
);
218 // 2nd Round: Add ParentTaxonFk to each taxon
219 success
&= doPhase02(state
);
221 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
222 success
&= doPhase03(state
);
224 // 4nd Round: Add TreeIndex to each taxon
225 success
&= doPhase04(state
);
228 //"PHASE 4: Creating Inferred Synonyms...
229 success
&= doPhase05(state
, mapping
, synonymRelMapping
);
231 logger
.info("*** Finished Making " + pluralString
+ " ..." + getSuccessString(success
));
234 state
.setUnsuccessfull();
237 } catch (Exception e
) {
239 logger
.error(e
.getMessage());
240 state
.setUnsuccessfull();
245 private void initPreparedStatements(PesiExportState state
) throws SQLException
{
246 initTreeIndexStatement(state
);
247 initRankExpertsUpdateStmt(state
);
248 initRankUpdateStatement(state
);
250 initParentFkStatement(state
);
253 // Prepare TreeIndex-And-KingdomFk-Statement
254 private void initTreeIndexStatement(PesiExportState state
) throws SQLException
{
255 Connection connection
= state
.getConfig().getDestination().getConnection();
256 String parentTaxonFk_TreeIndex_KingdomFkSql
= "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?";
257 parentTaxonFk_TreeIndex_KingdomFkStmt
= connection
.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql
);
260 // Prepare TreeIndex-And-KingdomFk-Statement
261 private void initParentFkStatement(PesiExportState state
) throws SQLException
{
262 Connection connection
= state
.getConfig().getDestination().getConnection();
263 String parentTaxonFkSql
= "UPDATE Taxon SET ParentTaxonFk = ? WHERE TaxonId = ?";
264 parentTaxonFkStmt
= connection
.prepareStatement(parentTaxonFkSql
);
267 private void initRankUpdateStatement(PesiExportState state
) throws SQLException
{
268 Connection connection
= state
.getConfig().getDestination().getConnection();
269 String rankSql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
270 rankUpdateStmt
= connection
.prepareStatement(rankSql
);
273 private void initRankExpertsUpdateStmt(PesiExportState state
) throws SQLException
{
274 // String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
275 // "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
276 //TODO handle experts GUIDs
277 Connection connection
= state
.getConfig().getDestination().getConnection();
279 String sql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
280 " WHERE TaxonId = ?";
281 rankTypeExpertsUpdateStmt
= connection
.prepareStatement(sql
);
284 private boolean doPhase01(PesiExportState state
, PesiExportMapping mapping
, PesiExportMapping additionalSourceMapping
) throws SQLException
{
287 List
<TaxonBase
> list
;
288 boolean success
= true;
289 // Get the limit for objects to save within a single transaction.
290 int limit
= state
.getConfig().getLimitSave();
293 logger
.info("PHASE 1: Export Taxa...limit is " + limit
);
295 TransactionStatus txStatus
= startTransaction(true);
296 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
300 int partitionCount
= 0;
302 logger
.info("Taking snapshot at the beginning of phase 1 of taxonExport");
303 ProfilerController
.memorySnapshot();
304 while ((list
= getNextTaxonPartition(null, limit
, partitionCount
++, null)) != null ) {
306 logger
.debug("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
307 for (TaxonBase
<?
> taxon
: list
) {
308 doCount(count
++, modCount
, pluralString
);
309 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
310 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
312 if (! nvn
.isProtectedTitleCache()){
313 nvn
.setTitleCache(null, false);
315 if (! nvn
.isProtectedNameCache()){
316 nvn
.setNameCache(null, false);
318 if (! nvn
.isProtectedFullTitleCache()){
319 nvn
.setFullTitleCache(null, false);
321 if (! nvn
.isProtectedAuthorshipCache()){
322 nvn
.setAuthorshipCache(null, false);
326 success
&= mapping
.invoke(taxon
);
328 if (nvn
.getNomenclaturalReference() != null || StringUtils
.isNotBlank(nvn
.getNomenclaturalMicroReference() )){
329 additionalSourceMapping
.invoke(taxon
);
332 validatePhaseOne(taxon
, nvn
);
342 // Commit transaction
343 commitTransaction(txStatus
);
344 logger
.debug("Committed transaction.");
345 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
347 /*logger.warn("Taking snapshot at the end of the loop of phase 1 of taxonExport");
348 ProfilerController.memorySnapshot();
351 txStatus
= startTransaction(true);
352 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
356 logger
.info("No " + pluralString
+ " left to fetch.");
361 // Commit transaction
362 commitTransaction(txStatus
);
364 logger
.debug("Committed transaction.");
366 logger
.warn("Taking snapshot at the end of phase 1 of taxonExport");
367 ProfilerController
.memorySnapshot();
372 private void validatePhaseOne(TaxonBase
<?
> taxon
, NonViralName taxonName
) {
373 // Check whether some rules are violated
374 nomenclaturalCode
= taxonName
.getNomenclaturalCode();
375 String genusOrUninomial
= taxonName
.getGenusOrUninomial();
376 String specificEpithet
= taxonName
.getSpecificEpithet();
377 String infraSpecificEpithet
= taxonName
.getInfraSpecificEpithet();
378 String infraGenericEpithet
= taxonName
.getInfraGenericEpithet();
379 Integer rank
= getRankFk(taxonName
, nomenclaturalCode
);
382 logger
.error("Rank was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
385 // Check whether infraGenericEpithet is set correctly
386 // 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
387 // 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
389 int ancestorLevel
= 0;
390 if (taxonName
.getRank().equals(Rank
.SUBSPECIES())) {
391 // The accepted taxon two rank levels above should be of rank subgenus
394 if (taxonName
.getRank().equals(Rank
.SPECIES())) {
395 // The accepted taxon one rank level above should be of rank subgenus
398 if (ancestorLevel
> 0) {
399 if (validateAncestorOfSpecificRank(taxon
, ancestorLevel
, Rank
.SUBGENUS())) {
400 // The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
401 if (infraGenericEpithet
== null) {
402 logger
.warn("InfraGenericEpithet does not exist even though it should for: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
403 // maybe the taxon could be named here
408 if (infraGenericEpithet
== null && rank
.intValue() == 190) {
409 logger
.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
411 if (specificEpithet
!= null && rank
.intValue() < 216) {
412 logger
.warn("SpecificEpithet was determined for rank " + rank
+ " although it should only exist for ranks higher or equal to 220: TaxonName " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
414 if (infraSpecificEpithet
!= null && rank
.intValue() < 225) {
415 String message
= "InfraSpecificEpithet '" +infraSpecificEpithet
+ "' was determined for rank " + rank
+ " although it should only exist for ranks higher or equal to 230: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")";
416 if (StringUtils
.isNotBlank(infraSpecificEpithet
)){
417 logger
.warn(message
);
419 logger
.warn(message
);
423 if (infraSpecificEpithet
!= null && specificEpithet
== null) {
424 logger
.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
426 if (genusOrUninomial
== null) {
427 logger
.warn("GenusOrUninomial was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
434 * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists
438 private boolean doPhase02(PesiExportState state
) {
442 boolean success
= true;
443 // Get the limit for objects to save within a single transaction.
444 int limit
= state
.getConfig().getLimitSave();
448 logger
.info("PHASE 2: Make ParentFk and TreeIndex ... limit is " + limit
);
450 TransactionStatus txStatus
= startTransaction(true);
451 int partitionCount
= 0;
453 // ProfilerController.memorySnapshot();
454 while ((list
= getNextTaxonPartition(Taxon
.class, limit
, partitionCount
++, null)) != null ) {
456 logger
.info("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
457 for (Taxon taxon
: list
) {
458 for (TaxonNode node
: taxon
.getTaxonNodes()){
459 doCount(count
++, modCount
, pluralString
);
460 TaxonNode parentNode
= node
.getParent();
461 if (parentNode
!= null){
462 int childId
= state
.getDbId( taxon
);
463 int parentId
= state
.getDbId(parentNode
.getTaxon());
464 success
&= invokeParentTaxonFk(parentId
, childId
);
470 // Commit transaction
471 commitTransaction(txStatus
);
472 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
475 txStatus
= startTransaction(true);
476 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
480 logger
.info("No " + pluralString
+ " left to fetch.");
483 // Commit transaction
484 commitTransaction(txStatus
);
491 * Inserts the Biota Taxon if not yet exists.
493 * @throws SQLException
495 private void insertBiota(PesiExportState state
) {
497 ResultSet rs
= state
.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");
498 if (rs
.next() == false){
499 int biotaId
= state
.getConfig().getNameIdStart() -1 ;
500 String sqlInsertBiota
= "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +
501 " VALUES (" + biotaId
+ ", 0, 0, 'Superdomain', 'Biota', 'Biota', '<i>Biota</i>', 'Biota', '<i>Biota</i>', 1 , 'accepted')";
502 state
.getConfig().getDestination().update(sqlInsertBiota
);
504 } catch (SQLException e
) {
505 logger
.warn ("Biota could not be requested or inserted");
509 // 4th round: Add TreeIndex to each taxon
510 private boolean doPhase04(PesiExportState state
) {
511 boolean success
= true;
513 logger
.info("PHASE 4: Make TreeIndex ... ");
515 //TODO test if possible to move to phase 02
516 String sql
= " UPDATE Taxon SET ParentTaxonFk = (Select TaxonId from Taxon where RankFk = 0) " +
517 " WHERE (RankFk = 10) and TaxonStatusFk = 1 ";
518 state
.getConfig().getDestination().update(sql
);
520 state
.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
527 // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
528 private boolean doPhase02_OLD(PesiExportState state
) {
529 boolean success
= true;
530 if (! state
.getConfig().isDoTreeIndex()){
531 logger
.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
535 List
<Classification
> classificationList
= null;
536 logger
.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
538 // Specify starting ranks for tree traversing
539 rankList
.add(Rank
.KINGDOM());
540 rankList
.add(Rank
.GENUS());
542 // Specify where to stop traversing (value) when starting at a specific Rank (key)
543 rank2endRankMap
.put(Rank
.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
544 rank2endRankMap
.put(Rank
.KINGDOM(), Rank
.GENUS()); // excludes rank genus
546 StringBuffer treeIndex
= new StringBuffer();
548 // Retrieve list of classifications
549 TransactionStatus txStatus
= startTransaction(true);
550 logger
.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
551 classificationList
= getClassificationService().listClassifications(null, 0, null, null);
552 commitTransaction(txStatus
);
553 logger
.debug("Committed transaction.");
555 logger
.info("Fetched " + classificationList
.size() + " classification(s).");
557 setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex
, "TreeIndex", "TreeIndex", "TI"));
558 List
<TaxonNode
> rankSpecificRootNodes
;
559 for (Classification classification
: classificationList
) {
560 for (Rank rank
: rankList
) {
562 txStatus
= startTransaction(true);
563 logger
.info("Started transaction to fetch all rootNodes specific to Rank " + rank
.getLabel() + " ...");
565 rankSpecificRootNodes
= getClassificationService().loadRankSpecificRootNodes(classification
, rank
, null);
566 logger
.info("Fetched " + rankSpecificRootNodes
.size() + " RootNodes for Rank " + rank
.getLabel());
568 commitTransaction(txStatus
);
569 logger
.debug("Committed transaction.");
571 for (TaxonNode rootNode
: rankSpecificRootNodes
) {
572 txStatus
= startTransaction(false);
573 Rank endRank
= rank2endRankMap
.get(rank
);
574 if (endRank
!= null) {
575 logger
.debug("Started transaction to traverse childNodes of rootNode (" + rootNode
.getUuid() + ") till Rank " + endRank
.getLabel() + " ...");
577 logger
.debug("Started transaction to traverse childNodes of rootNode (" + rootNode
.getUuid() + ") till leaves are reached ...");
580 TaxonNode newNode
= getTaxonNodeService().load(rootNode
.getUuid());
582 if (isPesiTaxon(newNode
.getTaxon())){
583 TaxonNode parentNode
= newNode
.getParent();
584 if (rank
.equals(Rank
.KINGDOM())) {
585 treeIndex
= new StringBuffer();
586 treeIndex
.append("#");
588 // Get treeIndex from parentNode
589 if (parentNode
!= null) {
590 boolean annotationFound
= false;
591 Set
<Annotation
> annotations
= parentNode
.getAnnotations();
592 for (Annotation annotation
: annotations
) {
593 AnnotationType annotationType
= annotation
.getAnnotationType();
594 if (annotationType
!= null && annotationType
.equals(getTreeIndexAnnotationType())) {
595 treeIndex
= new StringBuffer(CdmUtils
.Nz(annotation
.getText()));
596 annotationFound
= true;
597 // logger.error("treeIndex: " + treeIndex);
601 if (!annotationFound
) {
602 // This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
603 logger
.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode
.getUuid() + ", Taxon: " + parentNode
.getTaxon().getUuid());
604 treeIndex
= new StringBuffer();
605 treeIndex
.append("#");
608 // TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
609 logger
.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode
.getUuid());
610 treeIndex
= new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
611 treeIndex
.append("#");
614 nomenclaturalCode
= newNode
.getTaxon().getName().getNomenclaturalCode();
615 kingdomFk
= PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
);
616 traverseTree(newNode
, parentNode
, treeIndex
, endRank
, state
);
619 logger
.debug("Taxon is not a PESI taxon: " + newNode
.getTaxon().getUuid());
625 commitTransaction(txStatus
);
626 logger
.debug("Committed transaction.");
627 } catch (Exception e
) {
628 logger
.error(e
.getMessage());
633 rankSpecificRootNodes
= null;
638 logger
.warn("Taking snapshot at the end of phase 2 of taxonExport");
639 ProfilerController
.memorySnapshot();
643 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
644 private boolean doPhase03(PesiExportState state
) {
647 boolean success
= true;
648 if (! state
.getConfig().isDoTreeIndex()){
649 logger
.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
652 // Get the limit for objects to save within a single transaction.
653 int limit
= state
.getConfig().getLimitSave();
655 List
<TaxonBase
> list
;
656 logger
.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
657 // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
660 TransactionStatus txStatus
= startTransaction(true);
661 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
662 int partitionCount
= 0;
663 while ((list
= getNextTaxonPartition(TaxonBase
.class, limit
, partitionCount
++, null)) != null) {
665 logger
.debug("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
666 for (TaxonBase
<?
> taxon
: list
) {
667 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
668 // Determine expertFk
669 // Integer expertFk = makeExpertFk(state, taxonName);
671 // // Determine speciesExpertFk
672 // Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
674 doCount(count
++, modCount
, pluralString
);
675 Integer typeNameFk
= getTypeNameFk(taxonName
, state
);
677 //TODO why are expertFks needed? (Andreas M.)
678 // if (expertFk != null || speciesExpertFk != null) {
679 invokeRankDataAndTypeNameFkAndKingdomFk(taxonName
, nomenclaturalCode
, state
.getDbId(taxon
),
680 typeNameFk
, kingdomFk
, state
);
687 // Commit transaction
688 commitTransaction(txStatus
);
689 logger
.debug("Committed transaction.");
690 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
694 txStatus
= startTransaction(true);
695 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
698 logger
.info("No " + pluralString
+ " left to fetch.");
703 // Commit transaction
704 commitTransaction(txStatus
);
706 logger
.debug("Committed transaction.");
707 logger
.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount
);
708 ProfilerController
.memorySnapshot();
712 // "PHASE 5: Creating Inferred Synonyms..."
713 private boolean doPhase05(PesiExportState state
, PesiExportMapping mapping
, PesiExportMapping synRelMapping
) throws SQLException
{
716 boolean success
= true;
717 // Get the limit for objects to save within a single transaction.
718 if (! state
.getConfig().isDoInferredSynonyms()){
719 logger
.info ("Ignore PHASE 5: Creating Inferred Synonyms...");
723 int limit
= state
.getConfig().getLimitSave();
724 // Create inferred synonyms for accepted taxa
725 logger
.info("PHASE 4: Creating Inferred Synonyms...");
727 // Determine the count of elements in datawarehouse database table Taxon
728 currentTaxonId
= determineTaxonCount(state
);
733 int pageSize
= limit
;
735 String inferredSynonymPluralString
= "Inferred Synonyms";
738 TransactionStatus txStatus
= startTransaction(true);
739 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
740 List
<TaxonBase
> taxonList
= null;
744 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", Rank
.SPECIES(), pageSize
, pageNumber
)).size() > 0) {
745 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
747 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
748 inferredSynonymsDataToBeSaved
.putAll(createInferredSynonymsForTaxonList(state
, mapping
,
749 synRelMapping
, taxonList
));
751 doCount(count
+= taxonList
.size(), modCount
, inferredSynonymPluralString
);
752 // Commit transaction
753 commitTransaction(txStatus
);
754 logger
.debug("Committed transaction.");
755 logger
.info("Exported " + (taxonList
.size()) + " " + inferredSynonymPluralString
+ ". Total: " + count
);
758 // Save Rank Data and KingdomFk for inferred synonyms
759 for (Integer taxonFk
: inferredSynonymsDataToBeSaved
.keySet()) {
760 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved
.get(taxonFk
), nomenclaturalCode
, taxonFk
, kingdomFk
, state
);
764 txStatus
= startTransaction(true);
765 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
767 // Increment pageNumber
771 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", Rank
.SUBSPECIES(), pageSize
, pageNumber
)).size() > 0) {
772 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
774 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
775 inferredSynonymsDataToBeSaved
.putAll(createInferredSynonymsForTaxonList(state
, mapping
,
776 synRelMapping
, taxonList
));
778 doCount(count
+= taxonList
.size(), modCount
, inferredSynonymPluralString
);
779 // Commit transaction
780 commitTransaction(txStatus
);
781 logger
.debug("Committed transaction.");
782 logger
.info("Exported " + taxonList
.size()+ " " + inferredSynonymPluralString
+ ". Total: " + count
);
785 // Save Rank Data and KingdomFk for inferred synonyms
786 for (Integer taxonFk
: inferredSynonymsDataToBeSaved
.keySet()) {
787 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved
.get(taxonFk
), nomenclaturalCode
, taxonFk
, kingdomFk
, state
);
791 txStatus
= startTransaction(true);
792 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
794 // Increment pageNumber
797 if (taxonList
.size() == 0) {
798 logger
.info("No " + parentPluralString
+ " left to fetch.");
802 logger
.warn("Taking snapshot at the end of phase 4 of taxonExport");
803 ProfilerController
.memorySnapshot();
805 // Commit transaction
806 commitTransaction(txStatus
);
807 logger
.warn("Taking snapshot at the end of phase 4 after commit of taxonExport");
808 ProfilerController
.memorySnapshot();
810 logger
.warn("Taking snapshot at the end of phase 4 after gc() of taxonExport");
811 ProfilerController
.memorySnapshot();
812 logger
.debug("Committed transaction.");
819 * @param synRelMapping
820 * @param currentTaxonId
822 * @param inferredSynonymsDataToBeSaved
825 private HashMap
<Integer
, TaxonNameBase
<?
, ?
>> createInferredSynonymsForTaxonList(PesiExportState state
,
826 PesiExportMapping mapping
, PesiExportMapping synRelMapping
, List
<TaxonBase
> taxonList
) {
829 Classification classification
= null;
830 List
<Synonym
> inferredSynonyms
= null;
831 boolean localSuccess
= true;
833 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
835 for (TaxonBase
<?
> taxonBase
: taxonList
) {
837 if (taxonBase
.isInstanceOf(Taxon
.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
838 acceptedTaxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
839 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
841 if (taxonName
.isInstanceOf(ZoologicalName
.class)) {
842 nomenclaturalCode
= taxonName
.getNomenclaturalCode();
843 kingdomFk
= PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
);
845 Set
<TaxonNode
> taxonNodes
= acceptedTaxon
.getTaxonNodes();
846 TaxonNode singleNode
= null;
848 if (taxonNodes
.size() > 0) {
849 // Determine the classification of the current TaxonNode
851 singleNode
= taxonNodes
.iterator().next();
852 if (singleNode
!= null) {
853 classification
= singleNode
.getClassification();
855 logger
.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() +")");
858 // Classification could not be determined directly from this TaxonNode
859 // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
860 if (taxonNodes
.size() == 0) {
861 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");
866 if (classification
!= null) {
868 TaxonNameBase name
= acceptedTaxon
.getName();
869 //if (name.isSpecies() || name.isInfraSpecific()){
870 inferredSynonyms
= getTaxonService().createAllInferredSynonyms(acceptedTaxon
, classification
, true);
872 // inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
873 if (inferredSynonyms
!= null) {
874 for (Synonym synonym
: inferredSynonyms
) {
875 // TaxonNameBase<?,?> synonymName = synonym.getName();
876 MarkerType markerType
=getUuidMarkerType(PesiTransformer
.uuidMarkerGuidIsMissing
, state
);
877 synonym
.addMarker(Marker
.NewInstance(markerType
, true));
878 // Both Synonym and its TaxonName have no valid Id yet
879 synonym
.setId(currentTaxonId
++);
882 localSuccess
&= mapping
.invoke(synonym
);
883 //get SynonymRelationship and export
884 if (synonym
.getSynonymRelations().isEmpty() ){
885 SynonymRelationship synRel
;
886 IdentifiableSource source
= synonym
.getSources().iterator().next();
887 if (source
.getIdNamespace().contains("Potential combination")){
888 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
889 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to potential combination");
890 } else if (source
.getIdNamespace().contains("Inferred Genus")){
891 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.INFERRED_GENUS_OF());
892 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to inferred genus");
893 } else if (source
.getIdNamespace().contains("Inferred Epithet")){
894 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
895 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to inferred epithet");
897 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.INFERRED_SYNONYM_OF());
898 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to inferred synonym");
901 localSuccess
&= synRelMapping
.invoke(synRel
);
903 logger
.warn("Synonym relationship export failed " + synonym
.getTitleCache() + " accepted taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
907 for (SynonymRelationship synRel
: synonym
.getSynonymRelations()){
908 localSuccess
&= synRelMapping
.invoke(synRel
);
910 logger
.warn("Synonym relationship export failed " + synonym
.getTitleCache() + " accepted taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
916 inferredSynonymsDataToBeSaved
.put(synonym
.getId(), synonym
.getName());
920 logger
.error(e
.getMessage());
924 logger
.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() + ")");
927 // logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
930 logger
.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase
.getUuid() + " (" + taxonBase
.getTitleCache() + ")");
933 return inferredSynonymsDataToBeSaved
;
938 * Handles names that do not appear in taxa
943 private boolean doNames(PesiExportState state
, PesiExportMapping additionalSourceMapping
) throws SQLException
{
945 boolean success
= true;
946 if (! state
.getConfig().isDoPureNames()){
947 logger
.info ("Ignore PHASE 1b: PureNames");
952 PesiExportMapping mapping
= getPureNameMapping(state
);
953 mapping
.initialize(state
);
956 List
<NonViralName
<?
>> list
;
958 // Get the limit for objects to save within a single transaction.
959 int limit
= state
.getConfig().getLimitSave();
962 logger
.info("PHASE 1b: Export Pure Names ...");
964 TransactionStatus txStatus
= startTransaction(true);
965 logger
.info("Started new transaction for Pure Names. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
967 int partitionCount
= 0;
968 while ((list
= getNextPureNamePartition(null, limit
, partitionCount
++)) != null ) {
970 logger
.info("Fetched " + list
.size() + " names without taxa. Exporting...");
971 for (TaxonNameBase
<?
,?
> taxonName
: list
) {
972 doCount(count
++, modCount
, pluralString
);
973 success
&= mapping
.invoke(taxonName
);
975 if (taxonName
.getNomenclaturalReference() != null || StringUtils
.isNotBlank(taxonName
.getNomenclaturalMicroReference() )){
976 additionalSourceMapping
.invoke(taxonName
);
980 // Commit transaction
981 commitTransaction(txStatus
);
982 logger
.debug("Committed transaction.");
983 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
987 txStatus
= startTransaction(true);
988 logger
.info("Started new transaction for PureNames. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
991 logger
.info("No " + pluralString
+ " left to fetch.");
993 // Commit transaction
994 commitTransaction(txStatus
);
995 logger
.debug("Committed transaction.");
996 } catch (Exception e
) {
997 logger
.error("Error occurred in pure name export");
1005 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
1006 * @param state The {@link PesiExportState PesiExportState}.
1007 * @return The count.
1009 private Integer
determineTaxonCount(PesiExportState state
) {
1010 Integer result
= null;
1011 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
1014 Source destination
= pesiConfig
.getDestination();
1015 sql
= "SELECT max(taxonId) FROM Taxon";
1016 destination
.setQuery(sql
);
1017 ResultSet resultSet
= destination
.getResultSet();
1020 result
= resultSet
.getInt(1);
1021 } catch (SQLException e
) {
1022 logger
.error("TaxonCount could not be determined: " + e
.getMessage());
1023 e
.printStackTrace();
1029 * Checks whether a parent at specific level has a specific Rank.
1030 * @param taxonName A {@link TaxonNameBase TaxonName}.
1031 * @param level The ancestor level.
1032 * @param ancestorRank The ancestor rank.
1033 * @return Whether a parent at a specific level has a specific Rank.
1035 private boolean validateAncestorOfSpecificRank(TaxonBase
<?
> taxonBase
, int level
, Rank ancestorRank
) {
1036 boolean result
= false;
1037 TaxonNode parentNode
= null;
1038 if (taxonBase
.isInstanceOf(Taxon
.class)){
1039 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
1040 // Get ancestor Taxon via TaxonNode
1041 Set
<TaxonNode
> taxonNodes
= taxon
.getTaxonNodes();
1042 if (taxonNodes
.size() == 1) {
1043 TaxonNode taxonNode
= taxonNodes
.iterator().next();
1044 if (taxonNode
!= null) {
1045 for (int i
= 0; i
< level
; i
++) {
1046 if (taxonNode
!= null) {
1047 taxonNode
= taxonNode
.getParent();
1050 parentNode
= taxonNode
;
1052 } else if (taxonNodes
.size() > 1) {
1053 logger
.error("This taxon has " + taxonNodes
.size() + " taxonNodes: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
1057 if (parentNode
!= null) {
1058 TaxonNode node
= CdmBase
.deproxy(parentNode
, TaxonNode
.class);
1059 Taxon parentTaxon
= node
.getTaxon();
1060 if (parentTaxon
!= null) {
1061 TaxonNameBase
<?
,?
> parentTaxonName
= parentTaxon
.getName();
1062 if (parentTaxonName
!= null && parentTaxonName
.getRank().equals(ancestorRank
)) {
1066 logger
.error("This TaxonNode has no Taxon: " + node
.getUuid());
1073 * Returns the AnnotationType for a given UUID.
1074 * @param uuid The Annotation UUID.
1075 * @param label The Annotation label.
1076 * @param text The Annotation text.
1077 * @param labelAbbrev The Annotation label abbreviation.
1078 * @return The AnnotationType.
1080 protected AnnotationType
getAnnotationType(UUID uuid
, String label
, String text
, String labelAbbrev
){
1081 AnnotationType annotationType
= (AnnotationType
)getTermService().find(uuid
);
1082 if (annotationType
== null) {
1083 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
1084 annotationType
.setUuid(uuid
);
1085 // annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1086 getTermService().save(annotationType
);
1088 return annotationType
;
1092 * Traverses the classification recursively and stores determined values for every Taxon.
1093 * @param childNode The {@link TaxonNode TaxonNode} to process.
1094 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1095 * @param treeIndex The TreeIndex at the current level.
1096 * @param fetchLevel Rank to stop fetching at.
1097 * @param state The {@link PesiExportState PesiExportState}.
1099 private void traverseTree(TaxonNode childNode
, TaxonNode parentNode
, StringBuffer treeIndex
, Rank fetchLevel
, PesiExportState state
) {
1100 // Traverse all branches from this childNode until specified fetchLevel is reached.
1101 StringBuffer localTreeIndex
= new StringBuffer(treeIndex
);
1102 Taxon childTaxon
= childNode
.getTaxon();
1103 if (childTaxon
!= null) {
1104 if (isPesiTaxon(childTaxon
)){
1105 Integer taxonId
= state
.getDbId(childTaxon
);
1106 TaxonNameBase
<?
,?
> childName
= childTaxon
.getName();
1107 if (taxonId
!= null) {
1108 Rank childRank
= childName
.getRank();
1109 if (childRank
!= null) {
1110 if (! childRank
.equals(fetchLevel
)) {
1112 localTreeIndex
.append(taxonId
+ "#");
1114 saveData(childNode
, parentNode
, localTreeIndex
, state
, taxonId
);
1116 // Store treeIndex as annotation for further use
1117 Annotation annotation
= Annotation
.NewInstance(localTreeIndex
.toString(), getTreeIndexAnnotationType(), Language
.DEFAULT());
1118 childNode
.addAnnotation(annotation
);
1120 for (TaxonNode newNode
: childNode
.getChildNodes()) {
1121 if (newNode
.getTaxon() != null && isPesiTaxon(newNode
.getTaxon())){
1122 traverseTree(newNode
, childNode
, localTreeIndex
, fetchLevel
, state
);
1127 // logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1131 logger
.error("Rank is NULL. FetchLevel can not be checked: " + childName
.getUuid() + " (" + childName
.getTitleCache() + ")");
1134 logger
.error("Taxon can not be found in state: " + childTaxon
.getUuid() + " (" + childTaxon
.getTitleCache() + ")");
1137 if (logger
.isDebugEnabled()){
1138 logger
.debug("Taxon is not a PESI taxon: " + childTaxon
.getUuid());
1143 logger
.error("Taxon is NULL for TaxonNode: " + childNode
.getUuid());
1148 * Stores values in database for every recursive round.
1149 * @param childNode The {@link TaxonNode TaxonNode} to process.
1150 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1151 * @param treeIndex The TreeIndex at the current level.
1152 * @param state The {@link PesiExportState PesiExportState}.
1153 * @param currentTaxonFk The TaxonFk to store the values for.
1155 private void saveData(TaxonNode childNode
, TaxonNode parentNode
, StringBuffer treeIndex
, PesiExportState state
, Integer currentTaxonFk
) {
1156 // We are differentiating kingdoms by the nomenclatural code for now.
1157 // This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1158 Taxon childTaxon
= childNode
.getTaxon();
1159 if (isPesiTaxon(childTaxon
)) {
1160 TaxonBase
<?
> parentTaxon
= null;
1161 if (parentNode
!= null) {
1162 parentTaxon
= parentNode
.getTaxon();
1166 invokeParentTaxonFkAndTreeIndex(state
.getDbId(parentTaxon
), currentTaxonFk
, treeIndex
);
1172 * Inserts values into the Taxon database table.
1173 * @param taxonName The {@link TaxonNameBase TaxonName}.
1174 * @param state The {@link PesiExportState PesiExportState}.
1175 * @param stmt The prepared statement.
1176 * @return Whether save was successful or not.
1178 protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk
, Integer currentTaxonFk
, StringBuffer treeIndex
) {
1180 if (parentTaxonFk
!= null) {
1181 parentTaxonFk_TreeIndex_KingdomFkStmt
.setInt(1, parentTaxonFk
);
1183 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(1, null);
1186 if (treeIndex
!= null) {
1187 parentTaxonFk_TreeIndex_KingdomFkStmt
.setString(2, treeIndex
.toString());
1189 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(2, null);
1192 if (currentTaxonFk
!= null) {
1193 parentTaxonFk_TreeIndex_KingdomFkStmt
.setInt(3, currentTaxonFk
);
1195 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(3, null);
1198 parentTaxonFk_TreeIndex_KingdomFkStmt
.executeUpdate();
1200 } catch (SQLException e
) {
1201 logger
.error("ParentTaxonFk (" + parentTaxonFk
==null?
"-":parentTaxonFk
+ ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk
== null?
"-" :currentTaxonFk
) + ": " + e
.getMessage());
1202 e
.printStackTrace();
1207 protected boolean invokeParentTaxonFk(Integer parentId
, Integer childId
) {
1209 parentTaxonFkStmt
.setInt(1, parentId
);
1210 parentTaxonFkStmt
.setInt(2, childId
);
1211 parentTaxonFkStmt
.executeUpdate();
1213 } catch (SQLException e
) {
1214 logger
.warn("ParentTaxonFk (" + parentId
==null?
"-":parentId
+ ") could not be inserted into database for taxon "+ (childId
== null?
"-" :childId
) + ": " + e
.getMessage());
1215 e
.printStackTrace();
1222 * Inserts Rank data and KingdomFk into the Taxon database table.
1223 * @param taxonName The {@link TaxonNameBase TaxonName}.
1224 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1225 * @param taxonFk The TaxonFk to store the values for.
1227 * @param kindomFk The KingdomFk.
1228 * @return Whether save was successful or not.
1230 private boolean invokeRankDataAndKingdomFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
, Integer taxonFk
, Integer kingdomFk
, PesiExportState state
) {
1232 Integer rankFk
= getRankFk(taxonName
, nomenclaturalCode
);
1233 if (rankFk
!= null) {
1234 rankUpdateStmt
.setInt(1, rankFk
);
1236 rankUpdateStmt
.setObject(1, null);
1239 String rankCache
= getRankCache(taxonName
, nomenclaturalCode
, state
);
1240 if (rankCache
!= null) {
1241 rankUpdateStmt
.setString(2, rankCache
);
1243 rankUpdateStmt
.setObject(2, null);
1246 if (kingdomFk
!= null) {
1247 rankUpdateStmt
.setInt(3, kingdomFk
);
1249 rankUpdateStmt
.setObject(3, null);
1252 if (taxonFk
!= null) {
1253 rankUpdateStmt
.setInt(4, taxonFk
);
1255 rankUpdateStmt
.setObject(4, null);
1258 rankUpdateStmt
.executeUpdate();
1260 } catch (SQLException e
) {
1261 logger
.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e
.getMessage());
1262 e
.printStackTrace();
1268 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1269 * @param taxonName The {@link TaxonNameBase TaxonName}.
1270 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1271 * @param taxonFk The TaxonFk to store the values for.
1272 * @param typeNameFk The TypeNameFk.
1274 * @param kindomFk The KingdomFk.
1275 * @param expertFk The ExpertFk.
1276 * @param speciesExpertFk The SpeciesExpertFk.
1277 * @return Whether save was successful or not.
1279 private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
,
1280 Integer taxonFk
, Integer typeNameFk
, Integer kingdomFkk
, PesiExportState state
) {
1283 Integer rankFk
= getRankFk(taxonName
, nomenclaturalCode
);
1284 if (rankFk
!= null) {
1285 rankTypeExpertsUpdateStmt
.setInt(index
++, rankFk
);
1287 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1290 String rankCache
= getRankCache(taxonName
, nomenclaturalCode
, state
);
1291 if (rankCache
!= null) {
1292 rankTypeExpertsUpdateStmt
.setString(index
++, rankCache
);
1294 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1297 if (typeNameFk
!= null) {
1298 rankTypeExpertsUpdateStmt
.setInt(index
++, typeNameFk
);
1300 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1303 if (kingdomFk
!= null) {
1304 rankTypeExpertsUpdateStmt
.setInt(index
++, kingdomFk
);
1306 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1309 // if (expertFk != null) {
1310 // rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1312 // rankTypeExpertsUpdateStmt.setObject(5, null);
1315 // //TODO handle experts GUIDS
1316 // if (speciesExpertFk != null) {
1317 // rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1319 // rankTypeExpertsUpdateStmt.setObject(6, null);
1322 if (taxonFk
!= null) {
1323 rankTypeExpertsUpdateStmt
.setInt(index
++, taxonFk
);
1325 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1328 rankTypeExpertsUpdateStmt
.executeUpdate();
1330 } catch (SQLException e
) {
1331 logger
.error("Data could not be inserted into database: " + e
.getMessage());
1332 e
.printStackTrace();
1334 } catch (Exception e
) {
1335 logger
.error("Some exception occurred: " + e
.getMessage());
1336 e
.printStackTrace();
1342 * Deletes all entries of database tables related to <code>Taxon</code>.
1343 * @param state The {@link PesiExportState PesiExportState}.
1344 * @return Whether the delete operation was successful or not.
1346 protected boolean doDelete(PesiExportState state
) {
1347 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
1350 Source destination
= pesiConfig
.getDestination();
1353 sql
= "DELETE FROM " + dbTableName
;
1354 destination
.setQuery(sql
);
1355 destination
.update(sql
);
1360 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1363 protected boolean isIgnore(PesiExportState state
) {
1364 return ! state
.getConfig().isDoTaxa();
1369 * Creates the kingdom fk.
1373 @SuppressWarnings("unused") //used by mapper
1374 private static Integer
getKingdomFk(TaxonNameBase taxonName
){
1375 return PesiTransformer
.nomenClaturalCode2Kingdom(taxonName
.getNomenclaturalCode());
1379 * Creates the parent fk.
1383 @SuppressWarnings("unused") //used by mapper
1384 private static Integer
getParentTaxonFk(TaxonBase
<?
> taxonBase
, PesiExportState state
){
1385 if (taxonBase
.isInstanceOf(Taxon
.class)){
1386 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
1387 if (! isMisappliedName(taxon
)){
1388 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1389 if (nodes
.size() == 0){
1390 if (taxon
.getName().getRank().isLower(Rank
.KINGDOM())){
1391 logger
.warn("Accepted taxon has no parent. " + taxon
.getTitleCache() + ", " + taxon
.getUuid());
1393 }else if (nodes
.size() > 1){
1394 logger
.warn("Taxon has more than 1 node attached. This is not supported by PESI export." + taxon
.getTitleCache() + ", " + taxon
.getUuid());
1396 Taxon parent
=nodes
.iterator().next().getParent().getTaxon();
1397 return state
.getDbId(parent
);
1405 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1406 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1410 @SuppressWarnings("unused") //used by mapper
1411 private static Integer
getRankFk(TaxonNameBase
<?
,?
> taxonName
) {
1412 return getRankFk(taxonName
, taxonName
.getNomenclaturalCode());
1417 * Returns the <code>RankFk</code> attribute.
1418 * @param taxonName The {@link TaxonNameBase TaxonName}.
1419 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1420 * @return The <code>RankFk</code> attribute.
1423 private static Integer
getRankFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
) {
1424 Integer result
= null;
1426 if (nomenclaturalCode
!= null) {
1427 if (taxonName
!= null) {
1428 if (taxonName
.getRank() == null) {
1429 logger
.warn("Rank is null: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1431 result
= PesiTransformer
.rank2RankId(taxonName
.getRank(), PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
));
1433 if (result
== null) {
1434 logger
.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
) + " and TaxonName " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1438 } catch (Exception e
) {
1439 e
.printStackTrace();
1445 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1446 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1450 @SuppressWarnings("unused") //used by mapper
1451 private static String
getRankCache(TaxonNameBase
<?
,?
> taxonName
, PesiExportState state
) {
1452 return getRankCache(taxonName
, taxonName
.getNomenclaturalCode(), state
);
1457 * Returns the <code>RankCache</code> attribute.
1458 * @param taxonName The {@link TaxonNameBase TaxonName}.
1459 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1461 * @return The <code>RankCache</code> attribute.
1464 private static String
getRankCache(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
, PesiExportState state
) {
1465 if (nomenclaturalCode
!= null) {
1466 return state
.getTransformer().rank2RankCache(taxonName
.getRank(), PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
));
1468 logger
.warn("No nomenclatural code defined for name " + taxonName
.getUuid());
1476 * Returns the <code>DisplayName</code> attribute.
1477 * @param taxon The {@link TaxonBase Taxon}.
1478 * @return The <code>DisplayName</code> attribute.
1481 @SuppressWarnings("unused") //used by Mapper
1482 private static String
getDisplayName(TaxonBase
<?
> taxon
) {
1483 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1484 String result
= getDisplayName(taxonName
);
1485 if (isMisappliedName(taxon
)){
1486 result
= result
+ " " + getAuthorString(taxon
);
1492 * Returns the <code>AuthorString</code> attribute.
1493 * @param taxonName The {@link TaxonNameBase TaxonName}.
1494 * @return The <code>AuthorString</code> attribute.
1497 @SuppressWarnings("unused") //used by mapper
1498 protected static String
getAuthorString(TaxonBase
<?
> taxon
) {
1500 String result
= null;
1501 boolean isNonViralName
= false;
1502 String authorshipCache
= null;
1503 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1504 if (taxonName
!= null && taxonName
.isInstanceOf(NonViralName
.class)){
1505 authorshipCache
= CdmBase
.deproxy(taxonName
, NonViralName
.class).getAuthorshipCache();
1506 isNonViralName
= true;
1508 result
= authorshipCache
;
1510 // For a misapplied names there are special rules
1511 if (isMisappliedName(taxon
)){
1512 if (taxon
.getSec() != null){
1513 String secTitle
= taxon
.getSec().getTitleCache();
1514 if (! secTitle
.startsWith("auct")){
1515 secTitle
= "sensu " + secTitle
;
1516 }else if (secTitle
.equals("auct")){ //may be removed once the title cache is generated correctly for references with title auct. #
1520 }else if (StringUtils
.isBlank(authorshipCache
)) {
1521 // Set authorshipCache to "auct."
1522 result
= PesiTransformer
.AUCT_STRING
;
1524 result
= PesiTransformer
.AUCT_STRING
;
1525 // result = authorshipCache;
1529 if (taxonName
== null){
1530 logger
.warn("TaxonName does not exist for taxon: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
1531 }else if (! isNonViralName
){
1532 logger
.warn("TaxonName is not of instance NonViralName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1535 if (StringUtils
.isBlank(result
)) {
1540 } catch (Exception e
) {
1541 e
.printStackTrace();
1549 * Returns the <code>DisplayName</code> attribute.
1550 * @param taxonName The {@link TaxonNameBase TaxonName}.
1551 * @return The <code>DisplayName</code> attribute.
1554 @SuppressWarnings("unused") //used by Mapper
1555 private static String
getDisplayName(TaxonNameBase
<?
,?
> taxonName
) {
1557 if (taxonName
== null) {
1560 INonViralNameCacheStrategy
<NonViralName
<?
>> cacheStrategy
= getCacheStrategy(taxonName
);
1561 HTMLTagRules tagRules
= new HTMLTagRules().
1562 addRule(TagEnum
.name
, "i").
1563 addRule(TagEnum
.nomStatus
, "@status@");
1565 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1566 String result
= cacheStrategy
.getFullTitleCache(nvn
, tagRules
);
1567 cacheStrategy
= null;
1569 return result
.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");
1575 * Returns the <code>WebShowName</code> attribute for a taxon.
1576 * @param taxonName The {@link TaxonNameBase TaxonName}.
1577 * @return The <code>WebShowName</code> attribute.
1580 @SuppressWarnings("unused")
1581 private static String
getWebShowName(TaxonBase
<?
> taxon
) {
1582 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1583 String result
= getWebShowName(taxonName
);
1584 if (isMisappliedName(taxon
)){
1585 result
= result
+ " " + getAuthorString(taxon
);
1591 * Returns the <code>WebShowName</code> attribute.
1592 * @param taxonName The {@link TaxonNameBase TaxonName}.
1593 * @return The <code>WebShowName</code> attribute.
1596 private static String
getWebShowName(TaxonNameBase
<?
,?
> taxonName
) {
1598 if (taxonName
== null) {
1601 INonViralNameCacheStrategy
<NonViralName
<?
>> cacheStrategy
= getCacheStrategy(taxonName
);
1603 HTMLTagRules tagRules
= new HTMLTagRules().addRule(TagEnum
.name
, "i");
1604 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1605 String result
= cacheStrategy
.getTitleCache(nvn
, tagRules
);
1606 cacheStrategy
= null;
1614 * Returns the <code>WebSearchName</code> attribute.
1615 * @param taxonName The {@link NonViralName NonViralName}.
1616 * @return The <code>WebSearchName</code> attribute.
1619 @SuppressWarnings("unused")
1620 private static String
getWebSearchName(TaxonNameBase
<?
,?
> taxonName
) {
1622 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1623 NonViralNameDefaultCacheStrategy
<NonViralName
<?
>> strategy
= getCacheStrategy(nvn
);
1624 String result
= strategy
.getNameCache(nvn
);
1632 * Returns the <code>FullName</code> attribute.
1633 * @param taxonName The {@link NonViralName NonViralName}.
1634 * @return The <code>FullName</code> attribute.
1637 @SuppressWarnings("unused")
1638 private static String
getFullName(TaxonNameBase taxonName
) {
1640 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1641 String result
= getCacheStrategy(nvn
).getTitleCache(nvn
);
1642 Iterator
<TaxonBase
> taxa
= taxonName
.getTaxa().iterator();
1643 if (taxonName
.getTaxa().size() >0){
1644 if (taxonName
.getTaxa().size() == 1){
1645 TaxonBase taxon
= taxa
.next();
1646 if (isMisappliedName(taxon
)){
1647 result
= result
+ " " + getAuthorString(taxon
);
1658 * Returns the <code>FullName</code> attribute.
1659 * @param taxon The {@link TaxonBase taxon}.
1660 * @return The <code>FullName</code> attribute.
1663 /*@SuppressWarnings("unused")
1664 private static String getFullName(TaxonBase taxon) {
1666 TaxonNameBase name = taxon.getName();
1667 String result = getFullName(name);
1668 if (isMisappliedName(taxon)){
1669 result = result + " " + getAuthorString(taxon);
1677 * Returns the nomenclatural reference which is the reference
1678 * including the detail (microreference).
1679 * @param taxonName The {@link TaxonNameBase TaxonName}.
1680 * @return The <code>AuthorString</code> attribute.
1683 @SuppressWarnings("unused")
1684 private static String
getNomRefString(TaxonNameBase
<?
,?
> taxonName
) {
1685 INomenclaturalReference ref
= taxonName
.getNomenclaturalReference();
1686 return ref
== null ?
null : ref
.getNomenclaturalCitation(taxonName
.getNomenclaturalMicroReference());
1691 * Returns the <code>NameStatusFk</code> attribute.
1692 * @param taxonName The {@link TaxonNameBase TaxonName}.
1693 * @return The <code>NameStatusFk</code> attribute.
1696 @SuppressWarnings("unused")
1697 private static Integer
getNameStatusFk(TaxonNameBase
<?
,?
> taxonName
) {
1698 Integer result
= null;
1700 NomenclaturalStatus state
= getNameStatus(taxonName
);
1701 if (state
!= null) {
1702 result
= PesiTransformer
.nomStatus2nomStatusFk(state
.getType());
1708 * Returns the <code>NameStatusCache</code> attribute.
1709 * @param taxonName The {@link TaxonNameBase TaxonName}.
1710 * @return The <code>NameStatusCache</code> attribute.
1711 * @throws UndefinedTransformerMethodException
1714 @SuppressWarnings("unused")
1715 private static String
getNameStatusCache(TaxonNameBase taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1716 String result
= null;
1717 NomenclaturalStatus status
= getNameStatus(taxonName
);
1718 if (status
!= null) {
1719 result
= state
.getTransformer().getCacheByNomStatus(status
.getType());
1725 private static NomenclaturalStatus
getNameStatus(TaxonNameBase
<?
,?
> taxonName
) {
1727 if (taxonName
!= null && (taxonName
.isInstanceOf(NonViralName
.class))) {
1728 NonViralName
<?
> nonViralName
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1729 Set
<NomenclaturalStatus
> states
= nonViralName
.getStatus();
1730 if (states
.size() == 1) {
1731 NomenclaturalStatus status
= states
.iterator().next();
1733 } else if (states
.size() > 1) {
1734 logger
.error("This TaxonName has more than one Nomenclatural Status: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1738 } catch (Exception e
) {
1739 e
.printStackTrace();
1744 * Returns the <code>TaxonStatusFk</code> attribute.
1745 * @param taxonName The {@link TaxonNameBase TaxonName}.
1746 * @param state The {@link PesiExportState PesiExportState}.
1747 * @return The <code>TaxonStatusFk</code> attribute.
1750 private static Integer
getTaxonStatusFk(TaxonBase
<?
> taxon
, PesiExportState state
) {
1751 Integer result
= null;
1754 if (isMisappliedName(taxon
)) {
1755 Synonym synonym
= Synonym
.NewInstance(null, null);
1757 // This works as long as only the instance is important to differentiate between TaxonStatus.
1758 result
= PesiTransformer
.taxonBase2statusFk(synonym
); // Auct References are treated as Synonyms in Datawarehouse now.
1760 result
= PesiTransformer
.taxonBase2statusFk(taxon
);
1763 } catch (Exception e
) {
1764 e
.printStackTrace();
1770 * Returns the <code>TaxonStatusCache</code> attribute.
1771 * @param taxonName The {@link TaxonNameBase TaxonName}.
1772 * @param state The {@link PesiExportState PesiExportState}.
1773 * @return The <code>TaxonStatusCache</code> attribute.
1774 * @throws UndefinedTransformerMethodException
1777 @SuppressWarnings("unused")
1778 private static String
getTaxonStatusCache(TaxonBase
<?
> taxon
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1779 return state
.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon
, state
));
1783 * Returns the <code>TypeNameFk</code> attribute.
1784 * @param taxonName The {@link TaxonNameBase TaxonName}.
1785 * @param state The {@link PesiExportState PesiExportState}.
1786 * @return The <code>TypeNameFk</code> attribute.
1789 private static Integer
getTypeNameFk(TaxonNameBase
<?
,?
> taxonNameBase
, PesiExportState state
) {
1790 Integer result
= null;
1791 if (taxonNameBase
!= null) {
1792 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonNameBase
.getNameTypeDesignations();
1793 if (nameTypeDesignations
.size() == 1) {
1794 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1795 if (nameTypeDesignation
!= null) {
1796 TaxonNameBase
<?
,?
> typeName
= nameTypeDesignation
.getTypeName();
1797 if (typeName
!= null) {
1798 result
= state
.getDbId(typeName
);
1801 } else if (nameTypeDesignations
.size() > 1) {
1802 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonNameBase
.getUuid() + " (" + taxonNameBase
.getTitleCache() + ")");
1809 * Returns the <code>TypeFullnameCache</code> attribute.
1810 * @param taxonName The {@link TaxonNameBase TaxonName}.
1811 * @return The <code>TypeFullnameCache</code> attribute.
1814 @SuppressWarnings("unused")
1815 private static String
getTypeFullnameCache(TaxonNameBase
<?
,?
> taxonName
) {
1816 String result
= null;
1819 if (taxonName
!= null) {
1820 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonName
.getNameTypeDesignations();
1821 if (nameTypeDesignations
.size() == 1) {
1822 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1823 if (nameTypeDesignation
!= null) {
1824 TaxonNameBase
<?
,?
> typeName
= nameTypeDesignation
.getTypeName();
1825 if (typeName
!= null) {
1826 result
= typeName
.getTitleCache();
1829 } else if (nameTypeDesignations
.size() > 1) {
1830 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1834 } catch (Exception e
) {
1835 e
.printStackTrace();
1842 * Returns the <code>QualityStatusFk</code> attribute.
1843 * @param taxonName The {@link TaxonNameBase TaxonName}.
1844 * @return The <code>QualityStatusFk</code> attribute.
1847 private static Integer
getQualityStatusFk(TaxonNameBase taxonName
) {
1848 BitSet sources
= getSources(taxonName
);
1849 return PesiTransformer
.getQualityStatusKeyBySource(sources
, taxonName
);
1854 * Returns the <code>QualityStatusCache</code> attribute.
1855 * @param taxonName The {@link TaxonNameBase TaxonName}.
1856 * @return The <code>QualityStatusCache</code> attribute.
1857 * @throws UndefinedTransformerMethodException
1860 @SuppressWarnings("unused")
1861 private static String
getQualityStatusCache(TaxonNameBase taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1862 return state
.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName
));
1867 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1868 * @param taxonName The {@link TaxonNameBase TaxonName}.
1869 * @return The <code>TypeDesignationStatusFk</code> attribute.
1872 @SuppressWarnings("unused")
1873 private static Integer
getTypeDesignationStatusFk(TaxonNameBase
<?
,?
> taxonName
) {
1874 Integer result
= null;
1877 if (taxonName
!= null) {
1878 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1879 if (typeDesignations
.size() == 1) {
1880 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1881 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1882 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus
);
1883 } else if (typeDesignations
.size() > 1) {
1884 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1888 } catch (Exception e
) {
1889 e
.printStackTrace();
1895 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1896 * @param taxonName The {@link TaxonNameBase TaxonName}.
1897 * @return The <code>TypeDesignationStatusCache</code> attribute.
1900 @SuppressWarnings("unused")
1901 private static String
getTypeDesignationStatusCache(TaxonNameBase
<?
,?
> taxonName
) {
1902 String result
= null;
1905 if (taxonName
!= null) {
1906 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1907 if (typeDesignations
.size() == 1) {
1908 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1909 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1910 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus
);
1911 } else if (typeDesignations
.size() > 1) {
1912 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1916 } catch (Exception e
) {
1917 e
.printStackTrace();
1923 * Returns the <code>FossilStatusFk</code> attribute.
1924 * @param taxonName The {@link TaxonNameBase TaxonName}.
1925 * @return The <code>FossilStatusFk</code> attribute.
1928 @SuppressWarnings("unused")
1929 private static Integer
getFossilStatusFk(IdentifiableEntity
<?
> identEntity
, PesiExportState state
) {
1930 Integer result
= null;
1932 Set
<String
> fossilStatuus
= identEntity
.getExtensions(ErmsTransformer
.uuidFossilStatus
);
1933 if (fossilStatuus
.size() == 0){
1935 }else if (fossilStatuus
.size() > 1){
1936 logger
.warn("More than 1 fossil status given for " + identEntity
.getTitleCache() + " " + identEntity
.getUuid());
1938 String fossilStatus
= fossilStatuus
.iterator().next();
1940 int statusFk
= state
.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus
);
1945 * Returns the <code>FossilStatusCache</code> attribute.
1946 * @param taxonName The {@link TaxonNameBase TaxonName}.
1947 * @return The <code>FossilStatusCache</code> attribute.
1950 @SuppressWarnings("unused")
1951 private static String
getFossilStatusCache(IdentifiableEntity
<?
> identEntity
, PesiExportState state
) {
1952 String result
= null;
1953 Set
<String
> fossilStatuus
= identEntity
.getExtensions(ErmsTransformer
.uuidFossilStatus
);
1954 if (fossilStatuus
.size() == 0){
1957 for (String strFossilStatus
: fossilStatuus
){
1958 result
= CdmUtils
.concat(";", result
, strFossilStatus
);
1964 * Returns the <code>IdInSource</code> attribute.
1965 * @param taxonName The {@link TaxonNameBase TaxonName}.
1966 * @return The <code>IdInSource</code> attribute.
1969 @SuppressWarnings("unused")
1970 private static String
getIdInSource(IdentifiableEntity taxonName
) {
1971 String result
= null;
1974 Set
<IdentifiableSource
> sources
= getPesiSources(taxonName
);
1975 if (sources
.size() > 1){
1976 logger
.warn("There is > 1 Pesi source. This is not yet handled.");
1978 if (sources
.size() == 0){
1979 logger
.warn("There is no Pesi source!" +taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
1981 for (IdentifiableSource source
: sources
) {
1982 Reference
<?
> ref
= source
.getCitation();
1983 UUID refUuid
= ref
.getUuid();
1984 String idInSource
= source
.getIdInSource();
1985 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
1986 result
= idInSource
!= null ?
("NameId: " + source
.getIdInSource()) : null;
1987 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
1988 result
= idInSource
!= null ?
("TAX_ID: " + source
.getIdInSource()) : null;
1989 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
1990 result
= idInSource
!= null ?
("tu_id: " + source
.getIdInSource()) : null;
1991 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){ //Index Fungorum
1992 result
= idInSource
!= null ?
("if_id: " + source
.getIdInSource()) : null;
1994 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");};
1997 String sourceIdNameSpace
= source
.getIdNamespace();
1998 if (sourceIdNameSpace
!= null) {
1999 if (sourceIdNameSpace
.equals(PesiTransformer
.STR_NAMESPACE_NOMINAL_TAXON
)) {
2000 result
= idInSource
!= null ?
("Nominal Taxon from TAX_ID: " + source
.getIdInSource()):null;
2001 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_EPITHET_NAMESPACE
)) {
2002 result
= idInSource
!= null ?
("Inferred epithet from TAX_ID: " + source
.getIdInSource()) : null;
2003 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_GENUS_NAMESPACE
)) {
2004 result
= idInSource
!= null ?
("Inferred genus from TAX_ID: " + source
.getIdInSource()):null;
2005 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.POTENTIAL_COMBINATION_NAMESPACE
)) {
2006 result
= idInSource
!= null ?
("Potential combination from TAX_ID: " + source
.getIdInSource()):null;
2009 if (result
== null) {
2010 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +", sourceIdNameSpace: " + source
.getIdNamespace()+")");
2013 } catch (Exception e
) {
2014 e
.printStackTrace();
2015 logger
.error("An error occurs while creating idInSource..." + taxonName
.getUuid() + " (" + taxonName
.getTitleCache()+ e
.getMessage());
2018 if (result
== null) {
2019 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
2025 * Returns the idInSource for a given TaxonName only.
2026 * @param taxonName The {@link TaxonNameBase TaxonName}.
2027 * @return The idInSource.
2029 private static String
getIdInSourceOnly(IdentifiableEntity identEntity
) {
2030 String result
= null;
2032 // Get the sources first
2033 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
2035 // Determine the idInSource
2036 if (sources
.size() == 1) {
2037 IdentifiableSource source
= sources
.iterator().next();
2038 if (source
!= null) {
2039 result
= source
.getIdInSource();
2041 } else if (sources
.size() > 1) {
2044 for (IdentifiableSource source
: sources
) {
2045 result
+= source
.getIdInSource();
2046 if (count
< sources
.size()) {
2058 * Returns the Sources for a given TaxonName only.
2059 * @param taxonName The {@link TaxonNameBase TaxonName}.
2060 * @return The Sources.
2062 private static Set
<IdentifiableSource
> getPesiSources(IdentifiableEntity identEntity
) {
2063 Set
<IdentifiableSource
> sources
= new java
.util
.HashSet
<IdentifiableSource
>();
2066 if (identEntity
.isInstanceOf(TaxonNameBase
.class)){
2067 // Sources from TaxonName
2068 TaxonNameBase taxonName
= CdmBase
.deproxy(identEntity
, TaxonNameBase
.class);
2069 Set
<IdentifiableSource
> testSources
= identEntity
.getSources();
2070 sources
= filterPesiSources(identEntity
.getSources());
2072 if (sources
.size() == 0 && testSources
.size()>0){
2073 IdentifiableSource source
= testSources
.iterator().next();
2074 logger
.warn("There are sources, but they are no pesi sources!!!" + source
.getIdInSource() + " - " + source
.getIdNamespace() + " - "+source
.getCitation().generateTitle());
2076 if (sources
.size() > 1) {
2077 logger
.warn("This TaxonName has more than one Source: " + identEntity
.getUuid() + " (" + identEntity
.getTitleCache() + ")");
2080 // name has no PESI source, take sources from TaxonBase
2081 if (sources
== null || sources
.isEmpty()) {
2082 Set
<TaxonBase
> taxa
= taxonName
.getTaxonBases();
2083 for (TaxonBase taxonBase
: taxa
){
2084 sources
.addAll(filterPesiSources(taxonBase
.getSources()));
2089 }else if (identEntity
.isInstanceOf(TaxonBase
.class)){
2090 sources
= filterPesiSources(identEntity
.getSources());
2093 /*TODO: deleted only for testing the inferred synonyms
2094 if (sources == null || sources.isEmpty()) {
2095 logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2096 }else if (sources.size() > 1){
2097 logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2103 // return all sources with a PESI reference
2104 private static Set
<IdentifiableSource
> filterPesiSources(Set
<?
extends IdentifiableSource
> sources
) {
2105 Set
<IdentifiableSource
> result
= new HashSet
<IdentifiableSource
>();
2106 for (IdentifiableSource source
: sources
){
2107 Reference ref
= source
.getCitation();
2108 UUID refUuid
= ref
.getUuid();
2109 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
) ||
2110 refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)||
2111 refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)||
2112 refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
) ||
2113 refUuid
.equals(PesiTransformer
.uuidSourceRefAuct
)){
2121 * Returns the <code>GUID</code> attribute.
2122 * @param taxonName The {@link TaxonNameBase TaxonName}.
2123 * @return The <code>GUID</code> attribute.
2126 private static String
getGUID(TaxonBase
<?
> taxon
) {
2127 if (taxon
.getLsid() != null ){
2128 return taxon
.getLsid().getLsid();
2129 }else if (taxon
.hasMarker(PesiTransformer
.uuidMarkerGuidIsMissing
, true)){
2132 return taxon
.getUuid().toString();
2140 * Returns the <code>DerivedFromGuid</code> attribute.
2141 * @param taxonName The {@link TaxonNameBase TaxonName}.
2142 * @return The <code>DerivedFromGuid</code> attribute.
2145 @SuppressWarnings("unused")
2146 private static String
getDerivedFromGuid(TaxonBase
<?
> taxon
) {
2147 String result
= null;
2149 // The same as GUID for now
2150 result
= getGUID(taxon
);
2151 } catch (Exception e
) {
2152 e
.printStackTrace();
2158 * Returns the <code>CacheCitation</code> attribute.
2159 * @param taxonName The {@link TaxonNameBase TaxonName}.
2160 * @return The CacheCitation.
2163 @SuppressWarnings("unused")
2164 private static String
getCacheCitation(TaxonBase taxon
) {
2165 // !!! See also doPhaseUpdates
2167 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
2169 //TODO implement anew for taxa
2171 BitSet sources
= getSources(taxonName
);
2172 if (sources
.isEmpty()) {
2173 // logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2174 } else if (sources
.get(PesiTransformer
.SOURCE_ERMS
)) {
2175 // TODO: 19.08.2010: An import of CacheCitation does not exist in the ERMS import yet or it will be imported in a different way...
2176 // So the following code is some kind of harmless assumption.
2177 Set
<Extension
> extensions
= taxonName
.getExtensions();
2178 for (Extension extension
: extensions
) {
2179 if (extension
.getType().equals(cacheCitationExtensionType
)) {
2180 result
= extension
.getValue();
2184 String expertName
= getExpertName(taxon
);
2185 String webShowName
= getWebShowName(taxonName
);
2188 String idInSource
= getIdInSourceOnly(taxonName
);
2190 // build the cacheCitation
2191 if (expertName
!= null) {
2192 result
+= expertName
+ ". ";
2194 if (logger
.isDebugEnabled()){logger
.debug("ExpertName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");}
2196 if (webShowName
!= null) {
2197 result
+= webShowName
+ ". ";
2199 logger
.warn("WebShowName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
2202 if (getOriginalDB(taxonName
).equals("FaEu")) {
2203 result
+= "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
2204 } else if (getOriginalDB(taxonName
).equals("EM")) {
2205 result
+= "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
2208 if (idInSource
!= null) {
2209 result
+= idInSource
;
2211 logger
.warn("IdInSource could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
2214 } catch (Exception e
) {
2215 e
.printStackTrace();
2218 if (StringUtils
.isBlank(result
)) {
2226 * Returns the <code>OriginalDB</code> attribute.
2227 * @param taxonName The {@link TaxonNameBase TaxonName}.
2228 * @return The <code>OriginalDB</code> attribute.
2231 private static String
getOriginalDB(IdentifiableEntity identEntity
) {
2232 // Sources from TaxonName
2233 BitSet sources
= getSources(identEntity
);
2234 return PesiTransformer
.getOriginalDbBySources(sources
);
2238 * Returns the <code>LastAction</code> attribute.
2239 * @param taxonName The {@link TaxonNameBase TaxonName}.
2240 * @return The <code>LastAction</code> attribute.
2243 @SuppressWarnings("unused")
2244 private static String
getLastAction(IdentifiableEntity
<?
> identEntity
) {
2245 String result
= null;
2247 Set
<Extension
> extensions
= identEntity
.getExtensions();
2248 for (Extension extension
: extensions
) {
2249 if (extension
.getType().equals(lastActionExtensionType
)) {
2250 result
= extension
.getValue();
2253 } catch (Exception e
) {
2254 e
.printStackTrace();
2260 * Returns the <code>LastActionDate</code> attribute.
2261 * @param taxonName The {@link TaxonNameBase TaxonName}.
2262 * @return The <code>LastActionDate</code> attribute.
2265 @SuppressWarnings({ "unused" })
2266 private static DateTime
getLastActionDate(IdentifiableEntity identEntity
) {
2267 DateTime result
= null;
2269 Set
<Extension
> extensions
= identEntity
.getExtensions();
2270 for (Extension extension
: extensions
) {
2271 if (extension
.getType().equals(lastActionDateExtensionType
)) {
2272 String dateTime
= extension
.getValue();
2273 if (dateTime
!= null) {
2274 DateTimeFormatter formatter
= DateTimeFormat
.forPattern("yyyy-MM-dd HH:mm:ss.S");
2275 result
= formatter
.parseDateTime(dateTime
);
2279 } catch (Exception e
) {
2280 e
.printStackTrace();
2286 * Returns the <code>ExpertName</code> attribute.
2287 * @param taxonName The {@link TaxonNameBase TaxonName}.
2288 * @return The <code>ExpertName</code> attribute.
2291 @SuppressWarnings("unused")
2292 private static String
getExpertName(TaxonBase
<?
> taxonName
) {
2293 String result
= null;
2295 Set
<Extension
> extensions
= taxonName
.getExtensions();
2296 for (Extension extension
: extensions
) {
2297 if (extension
.getType().equals(expertNameExtensionType
)) {
2298 result
= extension
.getValue();
2301 } catch (Exception e
) {
2302 e
.printStackTrace();
2308 * Returns the <code>ExpertFk</code> attribute.
2309 * @param taxonName The {@link TaxonNameBase TaxonName}.
2310 * @param state The {@link PesiExportState PesiExportState}.
2311 * @return The <code>ExpertFk</code> attribute.
2314 private static Integer
getExpertFk(Reference
<?
> reference
, PesiExportState state
) {
2315 Integer result
= state
.getDbId(reference
);
2320 * Returns the <code>SpeciesExpertName</code> attribute.
2321 * @param taxonName The {@link TaxonNameBase TaxonName}.
2322 * @return The <code>SpeciesExpertName</code> attribute.
2325 @SuppressWarnings("unused")
2326 private static String
getSpeciesExpertName(TaxonBase
<?
> taxonName
) {
2327 String result
= null;
2329 Set
<Extension
> extensions
= taxonName
.getExtensions();
2330 for (Extension extension
: extensions
) {
2331 if (extension
.getType().equals(speciesExpertNameExtensionType
)) {
2332 result
= extension
.getValue();
2335 } catch (Exception e
) {
2336 e
.printStackTrace();
2342 * Returns the <code>SpeciesExpertFk</code> attribute.
2343 * @param reference The {@link Reference Reference}.
2344 * @param state The {@link PesiExportState PesiExportState}.
2345 * @return The <code>SpeciesExpertFk</code> attribute.
2348 private static Integer
getSpeciesExpertFk(Reference
<?
> reference
, PesiExportState state
) {
2349 Integer result
= state
.getDbId(reference
);
2355 * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
2356 * Identifiable Entity as a BitSet
2357 * @param identEntity
2360 private static BitSet
getSources(IdentifiableEntity
<?
> identEntity
){
2361 BitSet bitSet
= new BitSet();
2362 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
2363 for (IdentifiableSource source
: sources
) {
2364 Reference
<?
> ref
= source
.getCitation();
2365 UUID refUuid
= ref
.getUuid();
2366 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
2367 bitSet
.set(PesiTransformer
.SOURCE_EM
);
2368 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
2369 bitSet
.set(PesiTransformer
.SOURCE_FE
);
2370 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
2371 bitSet
.set(PesiTransformer
.SOURCE_ERMS
);
2372 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){
2373 bitSet
.set(PesiTransformer
.SOURCE_IF
);
2375 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");};
2382 protected static NonViralNameDefaultCacheStrategy
getCacheStrategy(TaxonNameBase
<?
, ?
> taxonName
) {
2383 taxonName
= CdmBase
.deproxy(taxonName
, TaxonNameBase
.class);
2384 NonViralNameDefaultCacheStrategy
<?
> cacheStrategy
;
2385 if (taxonName
.isInstanceOf(ZoologicalName
.class)){
2386 cacheStrategy
= zooNameStrategy
;
2387 }else if (taxonName
.isInstanceOf(BotanicalName
.class)) {
2388 cacheStrategy
= botanicalNameStrategy
;
2389 }else if (taxonName
.getClass().equals(NonViralName
.class)) {
2390 cacheStrategy
= nonViralNameStrategy
;
2391 }else if (taxonName
.getClass().equals(BacterialName
.class)) {
2392 cacheStrategy
= bacterialNameStrategy
;
2394 logger
.error("Unhandled taxon name type. Can't define strategy class");
2395 cacheStrategy
= botanicalNameStrategy
;
2397 return cacheStrategy
;
2401 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
2402 * @param relationship The {@link RelationshipBase Relationship}.
2403 * @param state The {@link PesiExportState PesiExportState}.
2404 * @return The <code>TaxonFk1</code> attribute.
2407 private static Integer
getTaxonFk1(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
) {
2409 return getObjectFk(relationship
, state
, true);
2413 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
2414 * @param relationship The {@link RelationshipBase Relationship}.
2415 * @param state The {@link PesiExportState PesiExportState}.
2416 * @return The <code>TaxonFk2</code> attribute.
2419 private static Integer
getTaxonFk2(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
) {
2420 return getObjectFk(relationship
, state
, false);
2424 * Returns the database key of an object in the given relationship.
2425 * @param relationship {@link RelationshipBase RelationshipBase}.
2426 * @param state {@link PesiExportState PesiExportState}.
2427 * @param isFrom A boolean value indicating whether the database key of the parent or child in this relationship is searched. <code>true</code> means the child is searched. <code>false</code> means the parent is searched.
2428 * @return The database key of an object in the given relationship.
2430 private static Integer
getObjectFk(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
, boolean isFrom
) {
2431 TaxonBase
<?
> taxonBase
= null;
2432 if (relationship
.isInstanceOf(TaxonRelationship
.class)) {
2433 TaxonRelationship tr
= (TaxonRelationship
)relationship
;
2434 taxonBase
= (isFrom
) ? tr
.getFromTaxon(): tr
.getToTaxon();
2435 } else if (relationship
.isInstanceOf(SynonymRelationship
.class)) {
2436 SynonymRelationship sr
= (SynonymRelationship
)relationship
;
2437 taxonBase
= (isFrom
) ? sr
.getSynonym() : sr
.getAcceptedTaxon();
2438 } else if (relationship
.isInstanceOf(NameRelationship
.class) || relationship
.isInstanceOf(HybridRelationship
.class)) {
2440 return state
.getDbId(state
.getCurrentFromObject());
2442 return state
.getDbId(state
.getCurrentToObject());
2445 if (taxonBase
!= null) {
2446 if (! isPesiTaxon(taxonBase
)){
2447 logger
.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase
.getId() + "/" + taxonBase
.getUuid() + "; TaxonRel: " + relationship
.getId() + "(" + relationship
.getType().getTitleCache() + ")");
2450 return state
.getDbId(taxonBase
);
2454 logger
.warn("No taxon found in state for relationship: " + relationship
.toString());
2459 * Returns the <code>RelQualifierCache</code> attribute.
2460 * @param relationship The {@link RelationshipBase Relationship}.
2461 * @return The <code>RelQualifierCache</code> attribute.
2464 @SuppressWarnings("unused")
2465 private static String
getRelQualifierCache(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
) {
2466 String result
= null;
2467 NomenclaturalCode code
= null;
2468 if (relationship
.isInstanceOf(TaxonRelationship
.class)){
2469 code
= CdmBase
.deproxy(relationship
, TaxonRelationship
.class).getToTaxon().getName().getNomenclaturalCode();
2470 }else if (relationship
.isInstanceOf(SynonymRelationship
.class)){
2471 code
= CdmBase
.deproxy(relationship
, SynonymRelationship
.class).getAcceptedTaxon().getName().getNomenclaturalCode();
2472 }else if (relationship
.isInstanceOf(NameRelationship
.class)){
2473 code
= CdmBase
.deproxy(relationship
, NameRelationship
.class).getFromName().getNomenclaturalCode();
2474 }else if (relationship
.isInstanceOf(HybridRelationship
.class)){
2475 code
= CdmBase
.deproxy(relationship
, HybridRelationship
.class).getParentName().getNomenclaturalCode();
2478 result
= state
.getConfig().getTransformer().getCacheByRelationshipType(relationship
, code
);
2480 logger
.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship
.getUuid());
2486 * Returns the <code>RelTaxonQualifierFk</code> attribute.
2487 * @param relationship The {@link RelationshipBase Relationship}.
2488 * @return The <code>RelTaxonQualifierFk</code> attribute.
2491 @SuppressWarnings("unused")
2492 private static Integer
getRelTaxonQualifierFk(RelationshipBase
<?
, ?
, ?
> relationship
) {
2493 return PesiTransformer
.taxonRelation2RelTaxonQualifierFk(relationship
);
2496 * Returns the <code>Notes</code> attribute.
2497 * @param relationship The {@link RelationshipBase Relationship}.
2498 * @return The <code>Notes</code> attribute.
2501 @SuppressWarnings("unused")
2502 private static String
getNotes(RelationshipBase
<?
, ?
, ?
> relationship
) {
2509 * Returns the CDM to PESI specific export mappings.
2510 * @return The {@link PesiExportMapping PesiExportMapping}.
2512 private PesiExportMapping
getMapping() {
2513 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2515 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2516 mapping
.addMapper(DbObjectMapper
.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2517 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter
, PesiExportState
.class));
2518 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter
, PesiExportState
.class));
2520 mapping
.addMapper(MethodMapper
.NewInstance("GUID", this));
2522 mapping
.addMapper(MethodMapper
.NewInstance("DerivedFromGuid", this));
2523 mapping
.addMapper(MethodMapper
.NewInstance("CacheCitation", this));
2524 mapping
.addMapper(MethodMapper
.NewInstance("AuthorString", this)); //For Taxon because Misallied Names are handled differently
2525 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this));
2528 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this));
2530 // FossilStatus (Fk, Cache)
2531 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusCache", this, IdentifiableEntity
.class, PesiExportState
.class));
2532 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusFk", this, IdentifiableEntity
.class, PesiExportState
.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2534 //handled by name mapping
2535 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2536 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2539 ExtensionType extensionTypeSpeciesExpertName
= (ExtensionType
)getTermService().find(PesiTransformer
.speciesExpertNameUuid
);
2540 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionTypeSpeciesExpertName
, "SpeciesExpertName"));
2541 ExtensionType extensionTypeExpertName
= (ExtensionType
)getTermService().find(PesiTransformer
.expertNameUuid
);
2542 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionTypeExpertName
, "ExpertName"));
2544 // mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class)); //by AM, doesn't work, FK exception
2545 mapping
.addMapper(ObjectChangeMapper
.NewInstance(TaxonBase
.class, TaxonNameBase
.class, "Name"));
2547 addNameMappers(mapping
);
2553 * Returns the CDM to PESI specific export mappings.
2555 * @return The {@link PesiExportMapping PesiExportMapping}.
2556 * @throws UndefinedTransformerMethodException
2558 private PesiExportMapping
getPureNameMapping(PesiExportState state
) throws UndefinedTransformerMethodException
{
2559 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2561 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2563 // mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2565 mapping
.addMapper(MethodMapper
.NewInstance("KingdomFk", this, TaxonNameBase
.class));
2566 mapping
.addMapper(MethodMapper
.NewInstance("RankFk", this, TaxonNameBase
.class));
2567 mapping
.addMapper(MethodMapper
.NewInstance("RankCache", this, TaxonNameBase
.class, PesiExportState
.class));
2568 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusFk", Types
.INTEGER
, PesiTransformer
.T_STATUS_UNACCEPTED
));
2569 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusCache", Types
.VARCHAR
, state
.getTransformer().getTaxonStatusCacheByKey( PesiTransformer
.T_STATUS_UNACCEPTED
)));
2570 mapping
.addMapper(DbStringMapper
.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
2571 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this, TaxonNameBase
.class));
2574 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this, TaxonNameBase
.class));
2576 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2577 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2579 addNameMappers(mapping
);
2580 //TODO add author mapper, TypeNameFk
2585 private void addNameMappers(PesiExportMapping mapping
) {
2586 mapping
.addMapper(DbStringMapper
.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2587 mapping
.addMapper(DbStringMapper
.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2588 mapping
.addMapper(DbStringMapper
.NewInstance("SpecificEpithet", "SpecificEpithet"));
2589 mapping
.addMapper(DbStringMapper
.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2591 // mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName")); //does not work as we need other cache strategy
2592 mapping
.addMapper(MethodMapper
.NewInstance("WebSearchName", this, TaxonNameBase
.class));
2594 // mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName")); //does not work as we need other cache strategy
2595 mapping
.addMapper(MethodMapper
.NewInstance("FullName", this, TaxonNameBase
.class));
2598 mapping
.addMapper(MethodMapper
.NewInstance("NomRefString", this, TaxonNameBase
.class));
2600 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusFk", this, TaxonNameBase
.class));
2601 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusCache", this, TaxonNameBase
.class, PesiExportState
.class));
2602 mapping
.addMapper(MethodMapper
.NewInstance("TypeFullnameCache", this, TaxonNameBase
.class));
2606 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusFk", this, TaxonNameBase
.class));
2607 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusCache", this, TaxonNameBase
.class, PesiExportState
.class));
2609 mapping
.addMapper(MethodMapper
.NewInstance("IdInSource", this, IdentifiableEntity
.class));
2610 mapping
.addMapper(MethodMapper
.NewInstance("OriginalDB", this, IdentifiableEntity
.class) );
2612 //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2616 private PesiExportMapping
getSynRelMapping() {
2617 PesiExportMapping mapping
= new PesiExportMapping(dbTableNameSynRel
);
2619 mapping
.addMapper(MethodMapper
.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase
.class, PesiExportState
.class));
2620 mapping
.addMapper(MethodMapper
.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase
.class, PesiExportState
.class));
2621 mapping
.addMapper(MethodMapper
.NewInstance("RelTaxonQualifierFk", this, RelationshipBase
.class));
2622 mapping
.addMapper(MethodMapper
.NewInstance("RelQualifierCache", this, RelationshipBase
.class, PesiExportState
.class));
2623 mapping
.addMapper(MethodMapper
.NewInstance("Notes", this, RelationshipBase
.class));
2628 private PesiExportMapping
getAdditionalSourceMapping(PesiExportState state
) throws UndefinedTransformerMethodException
{
2629 PesiExportMapping mapping
= new PesiExportMapping(dbTableAdditionalSourceRel
);
2631 mapping
.addMapper(IdMapper
.NewInstance("TaxonFk"));
2632 mapping
.addMapper(ObjectChangeMapper
.NewInstance(TaxonBase
.class, TaxonNameBase
.class, "Name"));
2634 mapping
.addMapper(DbObjectMapper
.NewInstance("NomenclaturalReference", "SourceFk"));
2635 mapping
.addMapper(DbObjectMapper
.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE
));
2637 //we have only nomenclatural references here
2638 mapping
.addMapper(DbConstantMapper
.NewInstance("SourceUseFk", Types
.INTEGER
, PesiTransformer
.NOMENCLATURAL_REFERENCE
));
2639 mapping
.addMapper(DbConstantMapper
.NewInstance("SourceUseCache", Types
.VARCHAR
, state
.getTransformer().getSourceUseCacheByKey( PesiTransformer
.NOMENCLATURAL_REFERENCE
)));
2641 mapping
.addMapper(DbStringMapper
.NewInstance("NomenclaturalMicroReference", "SourceDetail"));