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
.List
;
23 import java
.util
.UUID
;
25 import org
.apache
.commons
.lang
.StringUtils
;
26 import org
.apache
.log4j
.Logger
;
27 import org
.joda
.time
.DateTime
;
28 import org
.joda
.time
.format
.DateTimeFormat
;
29 import org
.joda
.time
.format
.DateTimeFormatter
;
30 import org
.springframework
.stereotype
.Component
;
31 import org
.springframework
.transaction
.TransactionStatus
;
33 import eu
.etaxonomy
.cdm
.api
.service
.TaxonServiceImpl
;
34 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
35 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
36 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
37 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbConstantMapper
;
38 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbExtensionMapper
;
39 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbLastActionMapper
;
40 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbObjectMapper
;
41 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbStringMapper
;
42 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.IdMapper
;
43 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.MethodMapper
;
44 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.ObjectChangeMapper
;
45 import eu
.etaxonomy
.cdm
.io
.pesi
.erms
.ErmsTransformer
;
46 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
47 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
48 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
49 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
50 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
51 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
52 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
53 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
54 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
55 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
56 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignationStatus
;
57 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
58 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
59 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
60 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
61 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
62 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
63 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
64 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
65 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
66 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
67 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
68 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
69 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
70 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
71 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
72 import eu
.etaxonomy
.cdm
.strategy
.cache
.HTMLTagRules
;
73 import eu
.etaxonomy
.cdm
.strategy
.cache
.TagEnum
;
74 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.BotanicNameDefaultCacheStrategy
;
75 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INonViralNameCacheStrategy
;
76 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.NonViralNameDefaultCacheStrategy
;
77 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.ZooNameNoMarkerCacheStrategy
;
80 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
81 * Inserts into DataWarehouse database table <code>Taxon</code>.
82 * It is divided into four phases:<p><ul>
83 * <li>Phase 1: Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.
84 * <li>Phase 2: Export of additional data: ParenTaxonFk and TreeIndex.
85 * <li>Phase 3: Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
86 * <li>Phase 4: Export of Inferred Synonyms.</ul>
92 public class PesiTaxonExport
extends PesiExportBase
{
93 private static final Logger logger
= Logger
.getLogger(PesiTaxonExport
.class);
94 private static final Class
<?
extends CdmBase
> standardMethodParameter
= TaxonBase
.class;
96 private static int modCount
= 1000;
97 private static final String dbTableName
= "Taxon";
98 private static final String pluralString
= "Taxa";
99 private static final String parentPluralString
= "Taxa";
100 private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt
;
101 private PreparedStatement rankTypeExpertsUpdateStmt
;
102 private PreparedStatement rankUpdateStmt
;
103 private NomenclaturalCode nomenclaturalCode
;
104 private Integer kingdomFk
;
105 private HashMap
<Rank
, Rank
> rank2endRankMap
= new HashMap
<Rank
, Rank
>();
106 private List
<Rank
> rankList
= new ArrayList
<Rank
>();
107 private static final UUID uuidTreeIndex
= UUID
.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");
108 private AnnotationType treeIndexAnnotationType
;
109 private static ExtensionType lastActionExtensionType
;
110 private static ExtensionType lastActionDateExtensionType
;
111 private static ExtensionType expertNameExtensionType
;
112 private static ExtensionType speciesExpertNameExtensionType
;
113 private static ExtensionType cacheCitationExtensionType
;
114 private static NonViralNameDefaultCacheStrategy
<?
> zooNameStrategy
= ZooNameNoMarkerCacheStrategy
.NewInstance();
115 private static NonViralNameDefaultCacheStrategy
<?
> botanicalNameStrategy
= BotanicNameDefaultCacheStrategy
.NewInstance();
119 * @return the treeIndexAnnotationType
121 protected AnnotationType
getTreeIndexAnnotationType() {
122 return treeIndexAnnotationType
;
126 * @param treeIndexAnnotationType the treeIndexAnnotationType to set
128 protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType
) {
129 this.treeIndexAnnotationType
= treeIndexAnnotationType
;
140 public PesiTaxonExport() {
145 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
148 public Class
<?
extends CdmBase
> getStandardMethodParameter() {
149 return standardMethodParameter
;
153 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
156 protected boolean doCheck(PesiExportState state
) {
157 boolean result
= true;
163 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
166 protected void doInvoke(PesiExportState state
) {
168 logger
.info("*** Started Making " + pluralString
+ " ...");
170 initPreparedStatements(state
);
172 // Stores whether this invoke was successful or not.
173 boolean success
= true;
175 // PESI: Clear the database table Taxon.
178 // Get specific mappings: (CDM) Taxon -> (PESI) Taxon
179 PesiExportMapping mapping
= getMapping();
181 // Initialize the db mapper
182 mapping
.initialize(state
);
184 // Find extensionTypes
185 lastActionExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.lastActionUuid
);
186 lastActionDateExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.lastActionDateUuid
);
187 expertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.expertNameUuid
);
188 speciesExpertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.speciesExpertNameUuid
);
189 cacheCitationExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.cacheCitationUuid
);
192 success
&= doPhase01(state
, mapping
);
194 //"PHASE 1b: Handle names without taxa ...
195 success
&= doNames(state
);
198 // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
199 success
&= doPhase02(state
);
201 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
202 success
&= doPhase03(state
);
205 //"PHASE 4: Creating Inferred Synonyms...
206 success
&= doPhase04(state
, mapping
);
208 //updates to TaxonStatus and others
209 success
&= doPhaseUpdates(state
);
212 logger
.info("*** Finished Making " + pluralString
+ " ..." + getSuccessString(success
));
215 state
.setUnsuccessfull();
218 } catch (SQLException e
) {
220 logger
.error(e
.getMessage());
221 state
.setUnsuccessfull();
226 //TODO check if this can all be done by getTaxonStatus
227 private boolean doPhaseUpdates(PesiExportState state
) {
230 String oldStatusFilter
= "= 7 "; //"= '" + PesiTransformer.T_STATUS_STR_UNACCEPTED + "' ";
231 String emStr
= PesiTransformer
.SOURCE_STR_EM
;
232 String feStr
= PesiTransformer
.SOURCE_STR_FE
;
233 String ifStr
= PesiTransformer
.SOURCE_STR_IF
;
236 String updateNotAccepted
= " UPDATE Taxon SET TaxonStatusFk = %d, TaxonStatusCache = '%s' " +
237 " WHERE OriginalDB = '%s' AND taxonstatusfk = 1 AND ParentTaxonFk %s AND RankFk > 180 ";
238 updateNotAccepted
= String
.format(updateNotAccepted
, 8, "NOT ACCEPTED: TAXONOMICALLY VALUELESS LOCAL OR SINGULAR BIOTYPE", emStr
, oldStatusFilter
);
239 int updated
= state
.getConfig().getDestination().update(updateNotAccepted
);
242 String updateAlternativeName
= "UPDATE Taxon SET TaxonStatusFk = 1, TaxonStatusCache = 'accepted' " +
243 " FROM RelTaxon RIGHT OUTER JOIN Taxon ON RelTaxon.TaxonFk1 = Taxon.TaxonId " +
244 " WHERE (RelTaxon.RelTaxonQualifierFk = 17) AND (Taxon.TaxonStatusFk %s) ";
245 updateAlternativeName
= String
.format(updateAlternativeName
, oldStatusFilter
);
246 updated
= state
.getConfig().getDestination().update(updateAlternativeName
);
248 String updateSynonyms
= " UPDATE Taxon SET TaxonStatusFk = 2, TaxonStatusCache = 'synonym' " +
249 " FROM RelTaxon RIGHT OUTER JOIN Taxon ON RelTaxon.TaxonFk1 = Taxon.TaxonId " +
250 " WHERE (RelTaxon.RelTaxonQualifierFk in (1, 3)) AND (Taxon.TaxonStatusFk %S)";
251 updateSynonyms
= String
.format(updateSynonyms
, oldStatusFilter
);
252 updated
= state
.getConfig().getDestination().update(updateSynonyms
);
254 // cache citation - check if this can't be done in getCacheCitation
255 // cache citation - FE
256 // String updateCacheCitationFE = " UPDATE Taxon " +
257 // " SET CacheCitation = IsNull(SpeciesExpertName + '. ', '') + WebShowName + '. Accessed through: Fauna Europaea at http://www.faunaeur.org/full_results.php?id=' + cast(TempFE_Id as varchar) " +
258 // " WHERE OriginalDb = '%s'";
259 // updateCacheCitationFE = String.format(updateCacheCitationFE, feStr);
260 // updated = state.getConfig().getDestination().update(updateCacheCitationFE);
262 // cache citation - EM
263 String updateCacheCitationEM
= " UPDATE Taxon " +
264 " SET CacheCitation = SpeciesExpertName + ' ' + WebShowName + '. Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=' + GUID " +
265 " WHERE OriginalDb = '%s'";
266 updateCacheCitationEM
= String
.format(updateCacheCitationEM
, emStr
);
267 updated
= state
.getConfig().getDestination().update(updateCacheCitationEM
);
269 // cache citation - IF
270 // String updateCacheCitationIF = " UPDATE Taxon " +
271 // " SET CacheCitation = IsNull(SpeciesExpertName + ' ', '') + WebShowName + '. Accessed through: Index Fungorum at http://www.indexfungorum.org/names/NamesRecord.asp?RecordID=' + cast(TempIF_Id as varchar) " +
272 // " WHERE OriginalDb = '%s'";
273 // updateCacheCitationIF = String.format(updateCacheCitationIF, ifStr);
274 // updated = state.getConfig().getDestination().update(updateCacheCitationIF);
279 private void initPreparedStatements(PesiExportState state
) throws SQLException
{
280 initTreeIndexStatement(state
);
281 initRankExpertsUpdateStmt(state
);
282 initRankUpdateStatement(state
);
285 // Prepare TreeIndex-And-KingdomFk-Statement
286 private void initTreeIndexStatement(PesiExportState state
) throws SQLException
{
287 Connection connection
= state
.getConfig().getDestination().getConnection();
288 String parentTaxonFk_TreeIndex_KingdomFkSql
= "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?";
289 parentTaxonFk_TreeIndex_KingdomFkStmt
= connection
.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql
);
292 private void initRankUpdateStatement(PesiExportState state
) throws SQLException
{
293 Connection connection
= state
.getConfig().getDestination().getConnection();
294 String rankSql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
295 rankUpdateStmt
= connection
.prepareStatement(rankSql
);
298 private void initRankExpertsUpdateStmt(PesiExportState state
) throws SQLException
{
299 // String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
300 // "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
301 //TODO handle experts GUIDs
302 Connection connection
= state
.getConfig().getDestination().getConnection();
304 String sql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
305 " WHERE TaxonId = ?";
306 rankTypeExpertsUpdateStmt
= connection
.prepareStatement(sql
);
309 private boolean doPhase01(PesiExportState state
, PesiExportMapping mapping
) throws SQLException
{
312 List
<TaxonBase
> list
;
313 boolean success
= true;
314 // Get the limit for objects to save within a single transaction.
315 int limit
= state
.getConfig().getLimitSave();
318 logger
.info("PHASE 1: Export Taxa...");
320 TransactionStatus txStatus
= startTransaction(true);
321 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
324 int partitionCount
= 0;
325 while ((list
= getNextTaxonPartition(null, limit
, partitionCount
++, null)).size() > 0 ) {
327 logger
.info("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
328 for (TaxonBase
<?
> taxon
: list
) {
329 doCount(count
++, modCount
, pluralString
);
330 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
331 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
333 if (! nvn
.isProtectedTitleCache()){
334 nvn
.setTitleCache(null, false);
336 if (! nvn
.isProtectedNameCache()){
337 nvn
.setNameCache(null, false);
339 if (! nvn
.isProtectedFullTitleCache()){
340 nvn
.setFullTitleCache(null, false);
342 if (! nvn
.isProtectedAuthorshipCache()){
343 nvn
.setAuthorshipCache(null, false);
346 success
&= mapping
.invoke(taxon
);
348 validatePhaseOne(taxon
, nvn
);
352 // Commit transaction
353 commitTransaction(txStatus
);
354 logger
.debug("Committed transaction.");
355 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
359 txStatus
= startTransaction(true);
360 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
362 if (list
.size() == 0) {
363 logger
.info("No " + pluralString
+ " left to fetch.");
365 // Commit transaction
366 commitTransaction(txStatus
);
367 logger
.debug("Committed transaction.");
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() + ")");
431 // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
432 private boolean doPhase02(PesiExportState state
) {
433 boolean success
= true;
434 if (! state
.getConfig().isDoTreeIndex()){
435 logger
.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
439 List
<Classification
> classificationList
= null;
440 logger
.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
442 // Specify starting ranks for tree traversing
443 rankList
.add(Rank
.KINGDOM());
444 rankList
.add(Rank
.GENUS());
446 // Specify where to stop traversing (value) when starting at a specific Rank (key)
447 rank2endRankMap
.put(Rank
.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
448 rank2endRankMap
.put(Rank
.KINGDOM(), Rank
.GENUS()); // excludes rank genus
450 StringBuffer treeIndex
= new StringBuffer();
452 // Retrieve list of classifications
453 TransactionStatus txStatus
= startTransaction(true);
454 logger
.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
455 classificationList
= getClassificationService().listClassifications(null, 0, null, null);
456 commitTransaction(txStatus
);
457 logger
.debug("Committed transaction.");
459 logger
.info("Fetched " + classificationList
.size() + " classification(s).");
461 setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex
, "TreeIndex", "TreeIndex", "TI"));
463 for (Classification classification
: classificationList
) {
464 for (Rank rank
: rankList
) {
466 txStatus
= startTransaction(true);
467 logger
.info("Started transaction to fetch all rootNodes specific to Rank " + rank
.getLabel() + " ...");
469 List
<TaxonNode
> rankSpecificRootNodes
= getClassificationService().loadRankSpecificRootNodes(classification
, rank
, null);
470 logger
.info("Fetched " + rankSpecificRootNodes
.size() + " RootNodes for Rank " + rank
.getLabel());
472 commitTransaction(txStatus
);
473 logger
.debug("Committed transaction.");
475 for (TaxonNode rootNode
: rankSpecificRootNodes
) {
476 txStatus
= startTransaction(false);
477 Rank endRank
= rank2endRankMap
.get(rank
);
478 if (endRank
!= null) {
479 logger
.debug("Started transaction to traverse childNodes of rootNode (" + rootNode
.getUuid() + ") till Rank " + endRank
.getLabel() + " ...");
481 logger
.debug("Started transaction to traverse childNodes of rootNode (" + rootNode
.getUuid() + ") till leaves are reached ...");
484 TaxonNode newNode
= getTaxonNodeService().load(rootNode
.getUuid());
486 if (isPesiTaxon(newNode
.getTaxon())){
487 TaxonNode parentNode
= newNode
.getParent();
488 if (rank
.equals(Rank
.KINGDOM())) {
489 treeIndex
= new StringBuffer();
490 treeIndex
.append("#");
492 // Get treeIndex from parentNode
493 if (parentNode
!= null) {
494 boolean annotationFound
= false;
495 Set
<Annotation
> annotations
= parentNode
.getAnnotations();
496 for (Annotation annotation
: annotations
) {
497 AnnotationType annotationType
= annotation
.getAnnotationType();
498 if (annotationType
!= null && annotationType
.equals(getTreeIndexAnnotationType())) {
499 treeIndex
= new StringBuffer(CdmUtils
.Nz(annotation
.getText()));
500 annotationFound
= true;
501 // logger.error("treeIndex: " + treeIndex);
505 if (!annotationFound
) {
506 // This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
507 logger
.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode
.getUuid() + ", Taxon: " + parentNode
.getTaxon().getUuid());
508 treeIndex
= new StringBuffer();
509 treeIndex
.append("#");
512 // TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
513 logger
.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode
.getUuid());
514 treeIndex
= new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
515 treeIndex
.append("#");
518 nomenclaturalCode
= newNode
.getTaxon().getName().getNomenclaturalCode();
519 kingdomFk
= PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
);
520 traverseTree(newNode
, parentNode
, treeIndex
, endRank
, state
);
522 logger
.debug("Taxon is not a PESI taxon: " + newNode
.getTaxon().getUuid());
527 commitTransaction(txStatus
);
528 logger
.debug("Committed transaction.");
536 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
537 private boolean doPhase03(PesiExportState state
) {
540 boolean success
= true;
541 if (! state
.getConfig().isDoTreeIndex()){
542 logger
.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
545 // Get the limit for objects to save within a single transaction.
546 int limit
= state
.getConfig().getLimitSave();
548 List
<TaxonBase
> list
;
549 logger
.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
550 // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
553 TransactionStatus txStatus
= startTransaction(true);
554 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
555 int partitionCount
= 0;
556 while ((list
= getNextTaxonPartition(TaxonBase
.class, limit
, partitionCount
++, null)).size() > 0) {
558 logger
.info("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
559 for (TaxonBase
<?
> taxon
: list
) {
560 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
561 // Determine expertFk
562 // Integer expertFk = makeExpertFk(state, taxonName);
564 // // Determine speciesExpertFk
565 // Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
567 doCount(count
++, modCount
, pluralString
);
568 Integer typeNameFk
= getTypeNameFk(taxonName
, state
);
570 //TODO why are expertFks needed? (Andreas M.)
571 // if (expertFk != null || speciesExpertFk != null) {
572 invokeRankDataAndTypeNameFkAndKingdomFk(taxonName
, nomenclaturalCode
, state
.getDbId(taxon
),
573 typeNameFk
, kingdomFk
);
577 // Commit transaction
578 commitTransaction(txStatus
);
579 logger
.debug("Committed transaction.");
580 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
584 txStatus
= startTransaction(true);
585 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
587 if (list
.size() == 0) {
588 logger
.info("No " + pluralString
+ " left to fetch.");
590 // Commit transaction
591 commitTransaction(txStatus
);
592 logger
.debug("Committed transaction.");
596 // "PHASE 4: Creating Inferred Synonyms..."
597 private boolean doPhase04(PesiExportState state
, PesiExportMapping mapping
) throws SQLException
{
600 boolean success
= true;
601 // Get the limit for objects to save within a single transaction.
602 if (! state
.getConfig().isDoTreeIndex()){
603 logger
.info ("Ignore PHASE 4: Creating Inferred Synonyms...");
607 int limit
= state
.getConfig().getLimitSave();
608 // Create inferred synonyms for accepted taxa
609 logger
.info("PHASE 4: Creating Inferred Synonyms...");
611 // Determine the count of elements in datawarehouse database table Taxon
612 Integer currentTaxonId
= determineTaxonCount(state
);
617 int pageSize
= limit
;
619 String inferredSynonymPluralString
= "Inferred Synonyms";
622 Classification classification
= null;
623 Taxon acceptedTaxon
= null;
624 TransactionStatus txStatus
= startTransaction(true);
625 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
626 List
<TaxonBase
> taxonList
= null;
627 List
<Synonym
> inferredSynonyms
= null;
628 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", null, pageSize
, pageNumber
)).size() > 0) {
629 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
631 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
632 for (TaxonBase
<?
> taxonBase
: taxonList
) {
634 if (taxonBase
.isInstanceOf(Taxon
.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
635 acceptedTaxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
636 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
638 if (taxonName
.isInstanceOf(ZoologicalName
.class)) {
639 nomenclaturalCode
= taxonName
.getNomenclaturalCode();
640 kingdomFk
= PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
);
642 Set
<TaxonNode
> taxonNodes
= acceptedTaxon
.getTaxonNodes();
643 TaxonNode singleNode
= null;
644 if (taxonNodes
.size() > 0) {
645 // Determine the classification of the current TaxonNode
646 singleNode
= taxonNodes
.iterator().next();
647 if (singleNode
!= null) {
648 classification
= singleNode
.getClassification();
650 logger
.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() +")");
653 // Classification could not be determined directly from this TaxonNode
654 // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
655 if (classification
== null) {
656 logger
.error("Classification could not be determined directly from this TaxonNode: " + singleNode
.getUuid() + "). " +
657 "This classification stored from another TaxonNode is used: " + classification
.getTitleCache());
661 if (classification
!= null) {
663 inferredSynonyms
= getTaxonService().createAllInferredSynonyms(acceptedTaxon
, classification
);
665 // inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
666 if (inferredSynonyms
!= null) {
667 for (Synonym synonym
: inferredSynonyms
) {
668 // TaxonNameBase<?,?> synonymName = synonym.getName();
670 // Both Synonym and its TaxonName have no valid Id yet
671 synonym
.setId(currentTaxonId
++);
673 doCount(count
++, modCount
, inferredSynonymPluralString
);
674 success
&= mapping
.invoke(synonym
);
676 // Add Rank Data and KingdomFk to hashmap for later saving
677 inferredSynonymsDataToBeSaved
.put(synonym
.getId(), synonym
.getName());
681 logger
.error(e
.getMessage());
685 logger
.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() + ")");
688 // logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
691 logger
.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase
.getUuid() + " (" + taxonBase
.getTitleCache() + ")");
695 // Commit transaction
696 commitTransaction(txStatus
);
697 logger
.debug("Committed transaction.");
698 logger
.info("Exported " + (count
- pastCount
) + " " + inferredSynonymPluralString
+ ". Total: " + count
);
701 // Save Rank Data and KingdomFk for inferred synonyms
702 for (Integer taxonFk
: inferredSynonymsDataToBeSaved
.keySet()) {
703 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved
.get(taxonFk
), nomenclaturalCode
, taxonFk
, kingdomFk
);
707 txStatus
= startTransaction(true);
708 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
710 // Increment pageNumber
713 if (taxonList
.size() == 0) {
714 logger
.info("No " + parentPluralString
+ " left to fetch.");
716 // Commit transaction
717 commitTransaction(txStatus
);
718 logger
.debug("Committed transaction.");
724 * Handles names that do not appear in taxa
729 private boolean doNames(PesiExportState state
) throws SQLException
{
731 boolean success
= true;
732 if (! state
.getConfig().isDoPureNames()){
733 logger
.info ("Ignore PHASE 1b: PureNames");
738 PesiExportMapping mapping
= getPureNameMapping();
739 mapping
.initialize(state
);
742 List
<NonViralName
<?
>> list
;
744 // Get the limit for objects to save within a single transaction.
745 int limit
= state
.getConfig().getLimitSave();
748 logger
.info("PHASE 1b: Export Pure Names ...");
750 TransactionStatus txStatus
= startTransaction(true);
751 logger
.info("Started new transaction for Pure Names. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
754 int partitionCount
= 0;
755 while ((list
= getNextPureNamePartition(null, limit
, partitionCount
++)) != null ) {
757 logger
.info("Fetched " + list
.size() + " names without taxa. Exporting...");
758 for (TaxonNameBase taxonName
: list
) {
759 doCount(count
++, modCount
, pluralString
);
760 success
&= mapping
.invoke(taxonName
);
763 // Commit transaction
764 commitTransaction(txStatus
);
765 logger
.debug("Committed transaction.");
766 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
770 txStatus
= startTransaction(true);
771 logger
.info("Started new transaction for PureNames. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
774 logger
.info("No " + pluralString
+ " left to fetch.");
776 // Commit transaction
777 commitTransaction(txStatus
);
778 logger
.debug("Committed transaction.");
779 } catch (Exception e
) {
780 logger
.error("Error occurred in pure name export");
788 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
789 * @param state The {@link PesiExportState PesiExportState}.
792 private Integer
determineTaxonCount(PesiExportState state
) {
793 Integer result
= null;
794 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
797 Source destination
= pesiConfig
.getDestination();
798 sql
= "SELECT max(taxonId) FROM Taxon";
799 destination
.setQuery(sql
);
800 ResultSet resultSet
= destination
.getResultSet();
803 result
= resultSet
.getInt(1);
804 } catch (SQLException e
) {
805 logger
.error("TaxonCount could not be determined: " + e
.getMessage());
812 * Checks whether a parent at specific level has a specific Rank.
813 * @param taxonName A {@link TaxonNameBase TaxonName}.
814 * @param level The ancestor level.
815 * @param ancestorRank The ancestor rank.
816 * @return Whether a parent at a specific level has a specific Rank.
818 private boolean validateAncestorOfSpecificRank(TaxonBase
<?
> taxonBase
, int level
, Rank ancestorRank
) {
819 boolean result
= false;
820 TaxonNode parentNode
= null;
821 if (taxonBase
.isInstanceOf(Taxon
.class)){
822 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
823 // Get ancestor Taxon via TaxonNode
824 Set
<TaxonNode
> taxonNodes
= taxon
.getTaxonNodes();
825 if (taxonNodes
.size() == 1) {
826 TaxonNode taxonNode
= taxonNodes
.iterator().next();
827 if (taxonNode
!= null) {
828 for (int i
= 0; i
< level
; i
++) {
829 if (taxonNode
!= null) {
830 taxonNode
= taxonNode
.getParent();
833 parentNode
= taxonNode
;
835 } else if (taxonNodes
.size() > 1) {
836 logger
.error("This taxon has " + taxonNodes
.size() + " taxonNodes: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
840 if (parentNode
!= null) {
841 TaxonNode node
= CdmBase
.deproxy(parentNode
, TaxonNode
.class);
842 Taxon parentTaxon
= node
.getTaxon();
843 if (parentTaxon
!= null) {
844 TaxonNameBase
<?
,?
> parentTaxonName
= parentTaxon
.getName();
845 if (parentTaxonName
!= null && parentTaxonName
.getRank().equals(ancestorRank
)) {
849 logger
.error("This TaxonNode has no Taxon: " + node
.getUuid());
856 * Returns the AnnotationType for a given UUID.
857 * @param uuid The Annotation UUID.
858 * @param label The Annotation label.
859 * @param text The Annotation text.
860 * @param labelAbbrev The Annotation label abbreviation.
861 * @return The AnnotationType.
863 protected AnnotationType
getAnnotationType(UUID uuid
, String label
, String text
, String labelAbbrev
){
864 AnnotationType annotationType
= (AnnotationType
)getTermService().find(uuid
);
865 if (annotationType
== null) {
866 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
867 annotationType
.setUuid(uuid
);
868 // annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
869 getTermService().save(annotationType
);
871 return annotationType
;
875 * Traverses the classification recursively and stores determined values for every Taxon.
876 * @param childNode The {@link TaxonNode TaxonNode} to process.
877 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
878 * @param treeIndex The TreeIndex at the current level.
879 * @param fetchLevel Rank to stop fetching at.
880 * @param state The {@link PesiExportState PesiExportState}.
882 private void traverseTree(TaxonNode childNode
, TaxonNode parentNode
, StringBuffer treeIndex
, Rank fetchLevel
, PesiExportState state
) {
883 // Traverse all branches from this childNode until specified fetchLevel is reached.
884 StringBuffer localTreeIndex
= new StringBuffer(treeIndex
);
885 Taxon childTaxon
= childNode
.getTaxon();
886 if (childTaxon
!= null) {
887 if (isPesiTaxon(childTaxon
)){
888 Integer taxonId
= state
.getDbId(childTaxon
);
889 TaxonNameBase
<?
,?
> childName
= childTaxon
.getName();
890 if (taxonId
!= null) {
891 Rank childRank
= childName
.getRank();
892 if (childRank
!= null) {
893 if (! childRank
.equals(fetchLevel
)) {
895 localTreeIndex
.append(taxonId
+ "#");
897 saveData(childNode
, parentNode
, localTreeIndex
, state
, taxonId
);
899 // Store treeIndex as annotation for further use
900 Annotation annotation
= Annotation
.NewInstance(localTreeIndex
.toString(), getTreeIndexAnnotationType(), Language
.DEFAULT());
901 childNode
.addAnnotation(annotation
);
903 for (TaxonNode newNode
: childNode
.getChildNodes()) {
904 if (newNode
.getTaxon() != null && isPesiTaxon(newNode
.getTaxon())){
905 traverseTree(newNode
, childNode
, localTreeIndex
, fetchLevel
, state
);
910 // logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
914 logger
.error("Rank is NULL. FetchLevel can not be checked: " + childName
.getUuid() + " (" + childName
.getTitleCache() + ")");
917 logger
.error("Taxon can not be found in state: " + childTaxon
.getUuid() + " (" + childTaxon
.getTitleCache() + ")");
920 if (logger
.isDebugEnabled()){
921 logger
.debug("Taxon is not a PESI taxon: " + childTaxon
.getUuid());
926 logger
.error("Taxon is NULL for TaxonNode: " + childNode
.getUuid());
931 * Stores values in database for every recursive round.
932 * @param childNode The {@link TaxonNode TaxonNode} to process.
933 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
934 * @param treeIndex The TreeIndex at the current level.
935 * @param state The {@link PesiExportState PesiExportState}.
936 * @param currentTaxonFk The TaxonFk to store the values for.
938 private void saveData(TaxonNode childNode
, TaxonNode parentNode
, StringBuffer treeIndex
, PesiExportState state
, Integer currentTaxonFk
) {
939 // We are differentiating kingdoms by the nomenclatural code for now.
940 // This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
941 Taxon childTaxon
= childNode
.getTaxon();
942 if (isPesiTaxon(childTaxon
)) {
943 TaxonBase
<?
> parentTaxon
= null;
944 if (parentNode
!= null) {
945 parentTaxon
= parentNode
.getTaxon();
949 invokeParentTaxonFkAndTreeIndex(state
.getDbId(parentTaxon
), currentTaxonFk
, treeIndex
);
955 * Inserts values into the Taxon database table.
956 * @param taxonName The {@link TaxonNameBase TaxonName}.
957 * @param state The {@link PesiExportState PesiExportState}.
958 * @param stmt The prepared statement.
959 * @return Whether save was successful or not.
961 protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk
, Integer currentTaxonFk
, StringBuffer treeIndex
) {
963 if (parentTaxonFk
!= null) {
964 parentTaxonFk_TreeIndex_KingdomFkStmt
.setInt(1, parentTaxonFk
);
966 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(1, null);
969 if (treeIndex
!= null) {
970 parentTaxonFk_TreeIndex_KingdomFkStmt
.setString(2, treeIndex
.toString());
972 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(2, null);
975 if (currentTaxonFk
!= null) {
976 parentTaxonFk_TreeIndex_KingdomFkStmt
.setInt(3, currentTaxonFk
);
978 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(3, null);
981 parentTaxonFk_TreeIndex_KingdomFkStmt
.executeUpdate();
983 } catch (SQLException e
) {
984 logger
.error("ParentTaxonFk (" + parentTaxonFk
==null?
"-":parentTaxonFk
+ ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk
== null?
"-" :currentTaxonFk
) + ": " + e
.getMessage());
991 * Inserts Rank data and KingdomFk into the Taxon database table.
992 * @param taxonName The {@link TaxonNameBase TaxonName}.
993 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
994 * @param taxonFk The TaxonFk to store the values for.
995 * @param kindomFk The KingdomFk.
996 * @return Whether save was successful or not.
998 private boolean invokeRankDataAndKingdomFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
, Integer taxonFk
, Integer kingdomFk
) {
1000 Integer rankFk
= getRankFk(taxonName
, nomenclaturalCode
);
1001 if (rankFk
!= null) {
1002 rankUpdateStmt
.setInt(1, rankFk
);
1004 rankUpdateStmt
.setObject(1, null);
1007 String rankCache
= getRankCache(taxonName
, nomenclaturalCode
);
1008 if (rankCache
!= null) {
1009 rankUpdateStmt
.setString(2, rankCache
);
1011 rankUpdateStmt
.setObject(2, null);
1014 if (kingdomFk
!= null) {
1015 rankUpdateStmt
.setInt(3, kingdomFk
);
1017 rankUpdateStmt
.setObject(3, null);
1020 if (taxonFk
!= null) {
1021 rankUpdateStmt
.setInt(4, taxonFk
);
1023 rankUpdateStmt
.setObject(4, null);
1026 rankUpdateStmt
.executeUpdate();
1028 } catch (SQLException e
) {
1029 logger
.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e
.getMessage());
1030 e
.printStackTrace();
1036 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1037 * @param taxonName The {@link TaxonNameBase TaxonName}.
1038 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1039 * @param taxonFk The TaxonFk to store the values for.
1040 * @param typeNameFk The TypeNameFk.
1041 * @param kindomFk The KingdomFk.
1042 * @param expertFk The ExpertFk.
1043 * @param speciesExpertFk The SpeciesExpertFk.
1044 * @return Whether save was successful or not.
1046 private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
,
1047 Integer taxonFk
, Integer typeNameFk
, Integer kingdomFkk
) {
1050 Integer rankFk
= getRankFk(taxonName
, nomenclaturalCode
);
1051 if (rankFk
!= null) {
1052 rankTypeExpertsUpdateStmt
.setInt(index
++, rankFk
);
1054 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1057 String rankCache
= getRankCache(taxonName
, nomenclaturalCode
);
1058 if (rankCache
!= null) {
1059 rankTypeExpertsUpdateStmt
.setString(index
++, rankCache
);
1061 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1064 if (typeNameFk
!= null) {
1065 rankTypeExpertsUpdateStmt
.setInt(index
++, typeNameFk
);
1067 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1070 if (kingdomFk
!= null) {
1071 rankTypeExpertsUpdateStmt
.setInt(index
++, kingdomFk
);
1073 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1076 // if (expertFk != null) {
1077 // rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1079 // rankTypeExpertsUpdateStmt.setObject(5, null);
1082 // //TODO handle experts GUIDS
1083 // if (speciesExpertFk != null) {
1084 // rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1086 // rankTypeExpertsUpdateStmt.setObject(6, null);
1089 if (taxonFk
!= null) {
1090 rankTypeExpertsUpdateStmt
.setInt(index
++, taxonFk
);
1092 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1095 rankTypeExpertsUpdateStmt
.executeUpdate();
1097 } catch (SQLException e
) {
1098 logger
.error("Data could not be inserted into database: " + e
.getMessage());
1099 e
.printStackTrace();
1105 * Deletes all entries of database tables related to <code>Taxon</code>.
1106 * @param state The {@link PesiExportState PesiExportState}.
1107 * @return Whether the delete operation was successful or not.
1109 protected boolean doDelete(PesiExportState state
) {
1110 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
1113 Source destination
= pesiConfig
.getDestination();
1116 sql
= "DELETE FROM " + dbTableName
;
1117 destination
.setQuery(sql
);
1118 destination
.update(sql
);
1123 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1126 protected boolean isIgnore(PesiExportState state
) {
1127 return ! state
.getConfig().isDoTaxa();
1132 * Creates the kingdom fk.
1136 @SuppressWarnings("unused") //used by mapper
1137 private static Integer
getKingdomFk(TaxonNameBase taxonName
){
1138 return PesiTransformer
.nomenClaturalCode2Kingdom(taxonName
.getNomenclaturalCode());
1142 * Creates the parent fk.
1146 @SuppressWarnings("unused") //used by mapper
1147 private static Integer
getParentTaxonFk(TaxonBase
<?
> taxonBase
, PesiExportState state
){
1148 if (taxonBase
.isInstanceOf(Taxon
.class)){
1149 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
1150 if (! isMisappliedName(taxon
)){
1151 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1152 if (nodes
.size() == 0){
1153 if (taxon
.getName().getRank().isLower(Rank
.KINGDOM())){
1154 logger
.warn("Accepted taxon has no parent. " + taxon
.getTitleCache() + ", " + taxon
.getUuid());
1156 }else if (nodes
.size() > 1){
1157 logger
.warn("Taxon has more than 1 node attached. This is not supported by PESI export." + taxon
.getTitleCache() + ", " + taxon
.getUuid());
1159 Taxon parent
=nodes
.iterator().next().getParent().getTaxon();
1160 return state
.getDbId(parent
);
1168 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1169 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1173 @SuppressWarnings("unused") //used by mapper
1174 private static Integer
getRankFk(TaxonNameBase
<?
,?
> taxonName
) {
1175 return getRankFk(taxonName
, taxonName
.getNomenclaturalCode());
1180 * Returns the <code>RankFk</code> attribute.
1181 * @param taxonName The {@link TaxonNameBase TaxonName}.
1182 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1183 * @return The <code>RankFk</code> attribute.
1186 private static Integer
getRankFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
) {
1187 Integer result
= null;
1189 if (nomenclaturalCode
!= null) {
1190 if (taxonName
!= null) {
1191 if (taxonName
.getRank() == null) {
1192 logger
.warn("Rank is null: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1194 result
= PesiTransformer
.rank2RankId(taxonName
.getRank(), PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
));
1196 if (result
== null) {
1197 logger
.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
) + " and TaxonName " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1201 } catch (Exception e
) {
1202 e
.printStackTrace();
1208 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1209 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1213 @SuppressWarnings("unused") //used by mapper
1214 private static String
getRankCache(TaxonNameBase
<?
,?
> taxonName
) {
1215 return getRankCache(taxonName
, taxonName
.getNomenclaturalCode());
1220 * Returns the <code>RankCache</code> attribute.
1221 * @param taxonName The {@link TaxonNameBase TaxonName}.
1222 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1223 * @return The <code>RankCache</code> attribute.
1226 private static String
getRankCache(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
) {
1227 String result
= null;
1229 if (nomenclaturalCode
!= null) {
1230 result
= PesiTransformer
.rank2RankCache(taxonName
.getRank(), PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
));
1232 } catch (Exception e
) {
1233 e
.printStackTrace();
1240 * Returns the <code>WebShowName</code> attribute.
1241 * @param taxonName The {@link TaxonNameBase TaxonName}.
1242 * @return The <code>WebShowName</code> attribute.
1245 private static String
getWebShowName(TaxonNameBase
<?
,?
> taxonName
) {
1247 if (taxonName
== null) {
1250 INonViralNameCacheStrategy cacheStrategy
= getCacheStrategy(taxonName
);
1252 HTMLTagRules tagRules
= new HTMLTagRules().addRule(TagEnum
.name
, "i");
1253 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1254 return cacheStrategy
.getTitleCache(nvn
, tagRules
);
1259 * Returns the <code>WebShowName</code> attribute for a taxon.
1260 * @param taxonName The {@link TaxonNameBase TaxonName}.
1261 * @return The <code>WebShowName</code> attribute.
1264 @SuppressWarnings("unused")
1265 private static String
getWebShowName(TaxonBase
<?
> taxon
) {
1266 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1267 String result
= getWebSearchName(taxonName
);
1268 if (isMisappliedName(taxon
)){
1269 result
= result
+ " " + getAuthorString(taxon
);
1276 * Returns the <code>WebSearchName</code> attribute.
1277 * @param taxonName The {@link NonViralName NonViralName}.
1278 * @return The <code>WebSearchName</code> attribute.
1281 @SuppressWarnings("unused")
1282 private static String
getWebSearchName(TaxonNameBase taxonName
) {
1284 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1285 NonViralNameDefaultCacheStrategy strategy
= getCacheStrategy(nvn
);
1286 String result
= strategy
.getNameCache(nvn
);
1292 * Returns the <code>FullName</code> attribute.
1293 * @param taxonName The {@link NonViralName NonViralName}.
1294 * @return The <code>FullName</code> attribute.
1297 @SuppressWarnings("unused")
1298 private static String
getFullName(TaxonNameBase taxonName
) {
1300 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1301 String result
= getCacheStrategy(nvn
).getTitleCache(nvn
);
1307 * Returns the nomenclatural reference which is the reference
1308 * including the detail (microreference).
1309 * @param taxonName The {@link TaxonNameBase TaxonName}.
1310 * @return The <code>AuthorString</code> attribute.
1313 @SuppressWarnings("unused")
1314 private static String
getNomRefString(TaxonNameBase
<?
,?
> taxonName
) {
1315 INomenclaturalReference ref
= taxonName
.getNomenclaturalReference();
1316 return ref
== null ?
null : ref
.getNomenclaturalCitation(taxonName
.getNomenclaturalMicroReference());
1321 * Returns the <code>AuthorString</code> attribute.
1322 * @param taxonName The {@link TaxonNameBase TaxonName}.
1323 * @return The <code>AuthorString</code> attribute.
1326 @SuppressWarnings("unused")
1327 private static String
getAuthorString(TaxonBase
<?
> taxon
) {
1329 String result
= null;
1330 boolean isNonViralName
= false;
1331 String authorshipCache
= null;
1332 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1333 if (taxonName
!= null && taxonName
.isInstanceOf(NonViralName
.class)){
1334 authorshipCache
= CdmBase
.deproxy(taxonName
, NonViralName
.class).getAuthorshipCache();
1335 isNonViralName
= true;
1337 result
= authorshipCache
;
1339 // For a misapplied names there are special rules
1340 if (isMisappliedName(taxon
)){
1341 if (taxon
.getSec() != null){
1342 String secTitle
= taxon
.getSec().getTitleCache();
1343 if (! secTitle
.startsWith("auct")){
1344 secTitle
= "sensu " + secTitle
;
1345 }else if (secTitle
.equals("auct")){ //may be removed once the title cache is generated correctly for references with title auct. #
1349 }else if (StringUtils
.isBlank(authorshipCache
)) {
1350 // Set authorshipCache to "auct."
1351 result
= PesiTransformer
.AUCT_STRING
;
1353 result
= PesiTransformer
.AUCT_STRING
;
1354 // result = authorshipCache;
1358 if (taxonName
== null){
1359 logger
.warn("TaxonName does not exist for taxon: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
1360 }else if (! isNonViralName
){
1361 logger
.warn("TaxonName is not of instance NonViralName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1364 if (StringUtils
.isBlank(result
)) {
1369 } catch (Exception e
) {
1370 e
.printStackTrace();
1378 * Checks whether a given taxon is a misapplied name.
1379 * @param taxon The {@link TaxonBase Taxon}.
1380 * @return Whether the given TaxonName is a misapplied name or not.
1382 private static boolean isMisappliedName(TaxonBase
<?
> taxon
) {
1383 return getAcceptedTaxonForMisappliedName(taxon
) != null;
1389 * Returns the first accepted taxon for this misapplied name.
1390 * If this misapplied name is not a misapplied name, <code>null</code> is returned.
1391 * @param taxon The {@link TaxonBase Taxon}.
1393 private static Taxon
getAcceptedTaxonForMisappliedName(TaxonBase
<?
> taxon
) {
1394 if (! taxon
.isInstanceOf(Taxon
.class)){
1397 Set
<TaxonRelationship
> taxonRelations
= CdmBase
.deproxy(taxon
, Taxon
.class).getRelationsFromThisTaxon();
1398 for (TaxonRelationship taxonRelationship
: taxonRelations
) {
1399 TaxonRelationshipType taxonRelationshipType
= taxonRelationship
.getType();
1400 if (taxonRelationshipType
.equals(TaxonRelationshipType
.MISAPPLIED_NAME_FOR())) {
1401 return taxonRelationship
.getToTaxon();
1409 * Returns the <code>DisplayName</code> attribute.
1410 * @param taxonName The {@link TaxonNameBase TaxonName}.
1411 * @return The <code>DisplayName</code> attribute.
1414 @SuppressWarnings("unused")
1415 private static String
getDisplayName(TaxonNameBase
<?
,?
> taxonName
) {
1417 if (taxonName
== null) {
1421 INonViralNameCacheStrategy cacheStrategy
= getCacheStrategy(taxonName
);
1423 HTMLTagRules tagRules
= new HTMLTagRules().
1424 addRule(TagEnum
.name
, "i").
1425 addRule(TagEnum
.nomStatus
, "@status@");
1427 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1428 String result
= cacheStrategy
.getFullTitleCache(nvn
, tagRules
);
1429 return result
.replaceAll("\\<@status@\\>.*\\</@status@\\>", "");
1435 * Returns the <code>NameStatusFk</code> attribute.
1436 * @param taxonName The {@link TaxonNameBase TaxonName}.
1437 * @return The <code>NameStatusFk</code> attribute.
1440 @SuppressWarnings("unused")
1441 private static Integer
getNameStatusFk(TaxonNameBase
<?
,?
> taxonName
) {
1442 Integer result
= null;
1444 NomenclaturalStatus state
= getNameStatus(taxonName
);
1445 if (state
!= null) {
1446 result
= PesiTransformer
.nomStatus2nomStatusFk(state
.getType());
1452 * Returns the <code>NameStatusCache</code> attribute.
1453 * @param taxonName The {@link TaxonNameBase TaxonName}.
1454 * @return The <code>NameStatusCache</code> attribute.
1455 * @throws UndefinedTransformerMethodException
1458 @SuppressWarnings("unused")
1459 private static String
getNameStatusCache(TaxonNameBase taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1460 String result
= null;
1461 NomenclaturalStatus status
= getNameStatus(taxonName
);
1462 if (status
!= null) {
1463 result
= state
.getTransformer().getCacheByNomStatus(status
.getType());
1469 private static NomenclaturalStatus
getNameStatus(TaxonNameBase
<?
,?
> taxonName
) {
1472 if (taxonName
!= null && (taxonName
.isInstanceOf(NonViralName
.class))) {
1473 NonViralName
<?
> nonViralName
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1474 Set
<NomenclaturalStatus
> states
= nonViralName
.getStatus();
1475 if (states
.size() == 1) {
1476 NomenclaturalStatus status
= states
.iterator().next();
1478 } else if (states
.size() > 1) {
1479 logger
.error("This TaxonName has more than one Nomenclatural Status: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1483 } catch (Exception e
) {
1484 e
.printStackTrace();
1489 * Returns the <code>TaxonStatusFk</code> attribute.
1490 * @param taxonName The {@link TaxonNameBase TaxonName}.
1491 * @param state The {@link PesiExportState PesiExportState}.
1492 * @return The <code>TaxonStatusFk</code> attribute.
1495 @SuppressWarnings("unused")
1496 private static Integer
getTaxonStatusFk(TaxonBase
<?
> taxon
, PesiExportState state
) {
1497 Integer result
= null;
1500 if (isMisappliedName(taxon
)) {
1501 Synonym synonym
= Synonym
.NewInstance(null, null);
1503 // This works as long as only the instance is important to differentiate between TaxonStatus.
1504 result
= PesiTransformer
.taxonBase2statusFk(synonym
); // Auct References are treated as Synonyms in Datawarehouse now.
1506 result
= PesiTransformer
.taxonBase2statusFk(taxon
);
1509 } catch (Exception e
) {
1510 e
.printStackTrace();
1516 * Returns the <code>TaxonStatusCache</code> attribute.
1517 * @param taxonName The {@link TaxonNameBase TaxonName}.
1518 * @param state The {@link PesiExportState PesiExportState}.
1519 * @return The <code>TaxonStatusCache</code> attribute.
1522 @SuppressWarnings("unused")
1523 private static String
getTaxonStatusCache(TaxonBase
<?
> taxon
, PesiExportState state
) {
1524 String result
= null;
1527 if (isMisappliedName(taxon
)) {
1528 Synonym synonym
= Synonym
.NewInstance(null, null);
1530 // This works as long as only the instance is important to differentiate between TaxonStatus.
1531 result
= PesiTransformer
.taxonBase2statusCache(synonym
); // Auct References are treated as Synonyms in Datawarehouse now.
1533 result
= PesiTransformer
.taxonBase2statusCache(taxon
);
1536 } catch (Exception e
) {
1537 e
.printStackTrace();
1543 * Returns the <code>TypeNameFk</code> attribute.
1544 * @param taxonName The {@link TaxonNameBase TaxonName}.
1545 * @param state The {@link PesiExportState PesiExportState}.
1546 * @return The <code>TypeNameFk</code> attribute.
1549 private static Integer
getTypeNameFk(TaxonNameBase
<?
,?
> taxonNameBase
, PesiExportState state
) {
1550 Integer result
= null;
1551 if (taxonNameBase
!= null) {
1552 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonNameBase
.getNameTypeDesignations();
1553 if (nameTypeDesignations
.size() == 1) {
1554 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1555 if (nameTypeDesignation
!= null) {
1556 TaxonNameBase
<?
,?
> typeName
= nameTypeDesignation
.getTypeName();
1557 if (typeName
!= null) {
1558 result
= state
.getDbId(typeName
);
1561 } else if (nameTypeDesignations
.size() > 1) {
1562 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonNameBase
.getUuid() + " (" + taxonNameBase
.getTitleCache() + ")");
1569 * Returns the <code>TypeFullnameCache</code> attribute.
1570 * @param taxonName The {@link TaxonNameBase TaxonName}.
1571 * @return The <code>TypeFullnameCache</code> attribute.
1574 @SuppressWarnings("unused")
1575 private static String
getTypeFullnameCache(TaxonNameBase
<?
,?
> taxonName
) {
1576 String result
= null;
1579 if (taxonName
!= null) {
1580 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonName
.getNameTypeDesignations();
1581 if (nameTypeDesignations
.size() == 1) {
1582 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1583 if (nameTypeDesignation
!= null) {
1584 TaxonNameBase
<?
,?
> typeName
= nameTypeDesignation
.getTypeName();
1585 if (typeName
!= null) {
1586 result
= typeName
.getTitleCache();
1589 } else if (nameTypeDesignations
.size() > 1) {
1590 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1594 } catch (Exception e
) {
1595 e
.printStackTrace();
1602 * Returns the <code>QualityStatusFk</code> attribute.
1603 * @param taxonName The {@link TaxonNameBase TaxonName}.
1604 * @return The <code>QualityStatusFk</code> attribute.
1607 private static Integer
getQualityStatusFk(TaxonNameBase taxonName
) {
1608 BitSet sources
= getSources(taxonName
);
1609 return PesiTransformer
.getQualityStatusKeyBySource(sources
);
1614 * Returns the <code>QualityStatusCache</code> attribute.
1615 * @param taxonName The {@link TaxonNameBase TaxonName}.
1616 * @return The <code>QualityStatusCache</code> attribute.
1617 * @throws UndefinedTransformerMethodException
1620 @SuppressWarnings("unused")
1621 private static String
getQualityStatusCache(TaxonNameBase taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1622 return state
.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName
));
1626 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1627 * @param taxonName The {@link TaxonNameBase TaxonName}.
1628 * @return The <code>TypeDesignationStatusFk</code> attribute.
1631 @SuppressWarnings("unused")
1632 private static Integer
getTypeDesignationStatusFk(TaxonNameBase
<?
,?
> taxonName
) {
1633 Integer result
= null;
1636 if (taxonName
!= null) {
1637 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1638 if (typeDesignations
.size() == 1) {
1639 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1640 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1641 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus
);
1642 } else if (typeDesignations
.size() > 1) {
1643 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1647 } catch (Exception e
) {
1648 e
.printStackTrace();
1654 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1655 * @param taxonName The {@link TaxonNameBase TaxonName}.
1656 * @return The <code>TypeDesignationStatusCache</code> attribute.
1659 @SuppressWarnings("unused")
1660 private static String
getTypeDesignationStatusCache(TaxonNameBase
<?
,?
> taxonName
) {
1661 String result
= null;
1664 if (taxonName
!= null) {
1665 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1666 if (typeDesignations
.size() == 1) {
1667 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1668 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1669 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus
);
1670 } else if (typeDesignations
.size() > 1) {
1671 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1675 } catch (Exception e
) {
1676 e
.printStackTrace();
1682 * Returns the <code>FossilStatusFk</code> attribute.
1683 * @param taxonName The {@link TaxonNameBase TaxonName}.
1684 * @return The <code>FossilStatusFk</code> attribute.
1687 @SuppressWarnings("unused")
1688 private static Integer
getFossilStatusFk(TaxonNameBase
<?
,?
> taxonNameBase
) {
1689 Integer result
= null;
1691 // if (taxonBase.isInstanceOf(Taxon.class)) {
1692 // taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1693 // Set<TaxonDescription> specimenDescription = taxon.;
1694 // result = PesiTransformer.fossil2FossilStatusId(fossil);
1700 * Returns the <code>FossilStatusCache</code> attribute.
1701 * @param taxonName The {@link TaxonNameBase TaxonName}.
1702 * @return The <code>FossilStatusCache</code> attribute.
1705 @SuppressWarnings("unused")
1706 private static String
getFossilStatusCache(TaxonNameBase
<?
,?
> taxonName
) {
1708 String result
= null;
1713 * Returns the <code>IdInSource</code> attribute.
1714 * @param taxonName The {@link TaxonNameBase TaxonName}.
1715 * @return The <code>IdInSource</code> attribute.
1718 @SuppressWarnings("unused")
1719 private static String
getIdInSource(IdentifiableEntity taxonName
) {
1720 String result
= null;
1723 Set
<IdentifiableSource
> sources
= getPesiSources(taxonName
);
1724 for (IdentifiableSource source
: sources
) {
1725 Reference
<?
> ref
= source
.getCitation();
1726 UUID refUuid
= ref
.getUuid();
1727 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
1728 result
= "NameId: " + source
.getIdInSource();
1729 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
1730 result
= "TAX_ID: " + source
.getIdInSource();
1731 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
1732 result
= "tu_id: " + source
.getIdInSource();
1733 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){ //INdex Fungorum
1734 result
= "if_id: " + source
.getIdInSource();
1736 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");};
1739 String sourceIdNameSpace
= source
.getIdNamespace();
1740 if (sourceIdNameSpace
!= null) {
1741 if (sourceIdNameSpace
.equals("originalGenusId")) {
1742 result
= "Nominal Taxon from TAX_ID: " + source
.getIdInSource();
1743 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_EPITHET_NAMESPACE
)) {
1744 result
= "Inferred epithet from TAX_ID: " + source
.getIdInSource();
1745 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_GENUS_NAMESPACE
)) {
1746 result
= "Inferred genus from TAX_ID: " + source
.getIdInSource();
1747 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.POTENTIAL_COMBINATION_NAMESPACE
)) {
1748 result
= "Potential combination from TAX_ID: " + source
.getIdInSource();
1752 } catch (Exception e
) {
1753 e
.printStackTrace();
1756 if (result
== null) {
1757 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
1763 * Returns the idInSource for a given TaxonName only.
1764 * @param taxonName The {@link TaxonNameBase TaxonName}.
1765 * @return The idInSource.
1767 private static String
getIdInSourceOnly(IdentifiableEntity identEntity
) {
1768 String result
= null;
1770 // Get the sources first
1771 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
1773 // Determine the idInSource
1774 if (sources
.size() == 1) {
1775 IdentifiableSource source
= sources
.iterator().next();
1776 if (source
!= null) {
1777 result
= source
.getIdInSource();
1779 } else if (sources
.size() > 1) {
1782 for (IdentifiableSource source
: sources
) {
1783 result
+= source
.getIdInSource();
1784 if (count
< sources
.size()) {
1796 * Returns the Sources for a given TaxonName only.
1797 * @param taxonName The {@link TaxonNameBase TaxonName}.
1798 * @return The Sources.
1800 private static Set
<IdentifiableSource
> getPesiSources(IdentifiableEntity identEntity
) {
1801 Set
<IdentifiableSource
> sources
= new java
.util
.HashSet
<IdentifiableSource
>();
1804 if (identEntity
.isInstanceOf(TaxonNameBase
.class)){
1805 // Sources from TaxonName
1806 TaxonNameBase taxonName
= CdmBase
.deproxy(identEntity
, TaxonNameBase
.class);
1807 sources
= filterPesiSources(identEntity
.getSources());
1808 if (sources
.size() > 1) {
1809 logger
.warn("This TaxonName has more than one Source: " + identEntity
.getUuid() + " (" + identEntity
.getTitleCache() + ")");
1812 // name has no PESI source, take sources from TaxonBase
1813 if (sources
== null || sources
.isEmpty()) {
1814 Set
<TaxonBase
> taxa
= taxonName
.getTaxonBases();
1815 for (TaxonBase taxonBase
: taxa
){
1816 sources
.addAll(filterPesiSources(taxonBase
.getSources()));
1821 }else if (identEntity
.isInstanceOf(TaxonBase
.class)){
1822 sources
= filterPesiSources(identEntity
.getSources());
1826 if (sources
== null || sources
.isEmpty()) {
1827 logger
.warn("This TaxonName has no PESI Sources: " + identEntity
.getUuid() + " (" + identEntity
.getTitleCache() +")");
1828 }else if (sources
.size() > 1){
1829 logger
.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity
.getUuid() + " (" + identEntity
.getTitleCache() +")");
1834 // return all sources with a PESI reference
1835 private static Set
<IdentifiableSource
> filterPesiSources(Set
<?
extends IdentifiableSource
> sources
) {
1836 Set
<IdentifiableSource
> result
= new HashSet
<IdentifiableSource
>();
1837 for (IdentifiableSource source
: sources
){
1838 Reference ref
= source
.getCitation();
1839 UUID refUuid
= ref
.getUuid();
1840 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
) ||
1841 refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)||
1842 refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)||
1843 refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
) ){
1851 * Returns the <code>GUID</code> attribute.
1852 * @param taxonName The {@link TaxonNameBase TaxonName}.
1853 * @return The <code>GUID</code> attribute.
1856 private static String
getGUID(TaxonBase
<?
> taxon
) {
1857 if (taxon
.getLsid() != null ){
1858 return taxon
.getLsid().getLsid();
1860 return taxon
.getUuid().toString();
1865 * Returns the <code>DerivedFromGuid</code> attribute.
1866 * @param taxonName The {@link TaxonNameBase TaxonName}.
1867 * @return The <code>DerivedFromGuid</code> attribute.
1870 @SuppressWarnings("unused")
1871 private static String
getDerivedFromGuid(TaxonBase
<?
> taxon
) {
1872 String result
= null;
1874 // The same as GUID for now
1875 result
= getGUID(taxon
);
1876 } catch (Exception e
) {
1877 e
.printStackTrace();
1883 * Returns the <code>CacheCitation</code> attribute.
1884 * @param taxonName The {@link TaxonNameBase TaxonName}.
1885 * @return The CacheCitation.
1888 @SuppressWarnings("unused")
1889 private static String
getCacheCitation(TaxonBase taxon
) {
1890 // !!! See also doPhaseUpdates
1892 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1894 //TODO implement anew for taxa
1896 BitSet sources
= getSources(taxonName
);
1897 if (sources
.isEmpty()) {
1898 // logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1899 } else if (sources
.get(PesiTransformer
.SOURCE_ERMS
)) {
1900 // 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...
1901 // So the following code is some kind of harmless assumption.
1902 Set
<Extension
> extensions
= taxonName
.getExtensions();
1903 for (Extension extension
: extensions
) {
1904 if (extension
.getType().equals(cacheCitationExtensionType
)) {
1905 result
= extension
.getValue();
1909 String expertName
= getExpertName(taxon
);
1910 String webShowName
= getWebShowName(taxonName
);
1913 String idInSource
= getIdInSourceOnly(taxonName
);
1915 // build the cacheCitation
1916 if (expertName
!= null) {
1917 result
+= expertName
+ ". ";
1919 if (logger
.isDebugEnabled()){logger
.debug("ExpertName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");}
1921 if (webShowName
!= null) {
1922 result
+= webShowName
+ ". ";
1924 logger
.warn("WebShowName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1927 if (getOriginalDB(taxonName
).equals("FaEu")) {
1928 result
+= "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
1929 } else if (getOriginalDB(taxonName
).equals("EM")) {
1930 result
+= "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
1933 if (idInSource
!= null) {
1934 result
+= idInSource
;
1936 logger
.warn("IdInSource could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1939 } catch (Exception e
) {
1940 e
.printStackTrace();
1943 if (StringUtils
.isBlank(result
)) {
1951 * Returns the <code>OriginalDB</code> attribute.
1952 * @param taxonName The {@link TaxonNameBase TaxonName}.
1953 * @return The <code>OriginalDB</code> attribute.
1956 private static String
getOriginalDB(IdentifiableEntity identEntity
) {
1957 // Sources from TaxonName
1958 BitSet sources
= getSources(identEntity
);
1959 return PesiTransformer
.getOriginalDbBySources(sources
);
1963 * Returns the <code>LastAction</code> attribute.
1964 * @param taxonName The {@link TaxonNameBase TaxonName}.
1965 * @return The <code>LastAction</code> attribute.
1968 @SuppressWarnings("unused")
1969 private static String
getLastAction(IdentifiableEntity
<?
> identEntity
) {
1970 String result
= null;
1972 Set
<Extension
> extensions
= identEntity
.getExtensions();
1973 for (Extension extension
: extensions
) {
1974 if (extension
.getType().equals(lastActionExtensionType
)) {
1975 result
= extension
.getValue();
1978 } catch (Exception e
) {
1979 e
.printStackTrace();
1985 * Returns the <code>LastActionDate</code> attribute.
1986 * @param taxonName The {@link TaxonNameBase TaxonName}.
1987 * @return The <code>LastActionDate</code> attribute.
1990 @SuppressWarnings({ "unused" })
1991 private static DateTime
getLastActionDate(IdentifiableEntity identEntity
) {
1992 DateTime result
= null;
1994 Set
<Extension
> extensions
= identEntity
.getExtensions();
1995 for (Extension extension
: extensions
) {
1996 if (extension
.getType().equals(lastActionDateExtensionType
)) {
1997 String dateTime
= extension
.getValue();
1998 if (dateTime
!= null) {
1999 DateTimeFormatter formatter
= DateTimeFormat
.forPattern("yyyy-MM-dd HH:mm:ss.S");
2000 result
= formatter
.parseDateTime(dateTime
);
2004 } catch (Exception e
) {
2005 e
.printStackTrace();
2011 * Returns the <code>ExpertName</code> attribute.
2012 * @param taxonName The {@link TaxonNameBase TaxonName}.
2013 * @return The <code>ExpertName</code> attribute.
2016 @SuppressWarnings("unused")
2017 private static String
getExpertName(TaxonBase
<?
> taxonName
) {
2018 String result
= null;
2020 Set
<Extension
> extensions
= taxonName
.getExtensions();
2021 for (Extension extension
: extensions
) {
2022 if (extension
.getType().equals(expertNameExtensionType
)) {
2023 result
= extension
.getValue();
2026 } catch (Exception e
) {
2027 e
.printStackTrace();
2033 * Returns the <code>ExpertFk</code> attribute.
2034 * @param taxonName The {@link TaxonNameBase TaxonName}.
2035 * @param state The {@link PesiExportState PesiExportState}.
2036 * @return The <code>ExpertFk</code> attribute.
2039 private static Integer
getExpertFk(Reference
<?
> reference
, PesiExportState state
) {
2040 Integer result
= state
.getDbId(reference
);
2045 * Returns the <code>SpeciesExpertName</code> attribute.
2046 * @param taxonName The {@link TaxonNameBase TaxonName}.
2047 * @return The <code>SpeciesExpertName</code> attribute.
2050 @SuppressWarnings("unused")
2051 private static String
getSpeciesExpertName(TaxonBase
<?
> taxonName
) {
2052 String result
= null;
2054 Set
<Extension
> extensions
= taxonName
.getExtensions();
2055 for (Extension extension
: extensions
) {
2056 if (extension
.getType().equals(speciesExpertNameExtensionType
)) {
2057 result
= extension
.getValue();
2060 } catch (Exception e
) {
2061 e
.printStackTrace();
2067 * Returns the <code>SpeciesExpertFk</code> attribute.
2068 * @param reference The {@link Reference Reference}.
2069 * @param state The {@link PesiExportState PesiExportState}.
2070 * @return The <code>SpeciesExpertFk</code> attribute.
2073 private static Integer
getSpeciesExpertFk(Reference
<?
> reference
, PesiExportState state
) {
2074 Integer result
= state
.getDbId(reference
);
2080 * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
2081 * Identifiable Entity as a BitSet
2082 * @param identEntity
2085 private static BitSet
getSources(IdentifiableEntity
<?
> identEntity
){
2086 BitSet bitSet
= new BitSet();
2087 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
2088 for (IdentifiableSource source
: sources
) {
2089 Reference
<?
> ref
= source
.getCitation();
2090 UUID refUuid
= ref
.getUuid();
2091 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
2092 bitSet
.set(PesiTransformer
.SOURCE_EM
);
2093 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
2094 bitSet
.set(PesiTransformer
.SOURCE_FE
);
2095 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
2096 bitSet
.set(PesiTransformer
.SOURCE_IF
);
2097 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){ //INdex Fungorum
2098 bitSet
.set(PesiTransformer
.SOURCE_ERMS
);
2100 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");};
2107 private static NonViralNameDefaultCacheStrategy
getCacheStrategy(TaxonNameBase
<?
, ?
> taxonName
) {
2108 NonViralNameDefaultCacheStrategy cacheStrategy
;
2109 if (taxonName
.isInstanceOf(ZoologicalName
.class)){
2110 cacheStrategy
= zooNameStrategy
;
2111 }else if (taxonName
.isInstanceOf(BotanicalName
.class)) {
2112 cacheStrategy
= botanicalNameStrategy
;
2114 logger
.error("Unhandled taxon name type. Can't define strategy class");
2115 cacheStrategy
= botanicalNameStrategy
;
2117 return cacheStrategy
;
2121 // * Returns the <code>SourceFk</code> attribute.
2122 // * @param taxonName The {@link TaxonNameBase TaxonName}.
2123 // * @param state The {@link PesiExportState PesiExportState}.
2124 // * @return The <code>SourceFk</code> attribute.
2126 // @SuppressWarnings("unused")
2127 // private static Integer getSourceFk(TaxonNameBase<?,?> taxonName, PesiExportState state) {
2128 // Integer result = null;
2131 // TaxonBase<?> taxonBase = getSourceTaxonBase(taxonName);
2133 // if (taxonBase != null) {
2134 // result = state.getDbId(taxonBase.getSec());
2136 // } catch (Exception e) {
2137 // e.printStackTrace();
2144 // * Determines the TaxonBase of a TaxonName.
2145 // * @param taxonName The {@link TaxonNameBase TaxonName}.
2146 // * @return The TaxonBase.
2148 // private static TaxonBase<?> getSourceTaxonBase(TaxonNameBase<?,?> taxonName) {
2149 // TaxonBase<?> taxonBase = null;
2150 // Set<Taxon> taxa = taxonName.getTaxa();
2151 // if (taxa.size() == 1) {
2152 // taxonBase =taxa.iterator().next();
2153 // } else if (taxa.size() > 1) {
2154 // logger.warn("This TaxonName has " + taxa.size() + " Taxa: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2157 // Set<Synonym> synonyms = taxonName.getSynonyms();
2158 // if (synonyms.size() == 1) {
2159 // taxonBase = synonyms.iterator().next();
2160 // } else if (synonyms.size() > 1) {
2161 // logger.warn("This TaxonName has " + synonyms.size() + " Synonyms: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2163 // return taxonBase;
2167 * Returns the CDM to PESI specific export mappings.
2168 * @return The {@link PesiExportMapping PesiExportMapping}.
2170 private PesiExportMapping
getMapping() {
2171 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2173 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2174 mapping
.addMapper(DbObjectMapper
.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2175 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter
, PesiExportState
.class));
2176 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter
, PesiExportState
.class));
2178 // QualityStatus (Fk, Cache)
2179 // extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidQualityStatus);
2180 // if (extensionType != null) {
2181 // mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "QualityStatusCache"));
2183 // mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this));
2185 // mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this)); // PesiTransformer.QualityStatusCache2QualityStatusFk?
2187 mapping
.addMapper(MethodMapper
.NewInstance("GUID", this));
2189 mapping
.addMapper(MethodMapper
.NewInstance("DerivedFromGuid", this));
2190 mapping
.addMapper(MethodMapper
.NewInstance("CacheCitation", this));
2191 mapping
.addMapper(MethodMapper
.NewInstance("AuthorString", this)); //For Taxon because Misallied Names are handled differently
2192 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this));
2194 //handled by name mapping
2195 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2196 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2198 ExtensionType extensionTypeSpeciesExpertName
= (ExtensionType
)getTermService().find(PesiTransformer
.speciesExpertNameUuid
);
2199 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionTypeSpeciesExpertName
, "SpeciesExpertName"));
2200 ExtensionType extensionTypeExpertName
= (ExtensionType
)getTermService().find(PesiTransformer
.expertNameUuid
);
2201 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionTypeExpertName
, "ExpertName"));
2203 // mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class)); //doesn't work, FK exceptioni
2204 mapping
.addMapper(ObjectChangeMapper
.NewInstance(TaxonBase
.class, TaxonNameBase
.class, "Name"));
2206 addNameMappers(mapping
);
2212 * Returns the CDM to PESI specific export mappings.
2213 * @return The {@link PesiExportMapping PesiExportMapping}.
2215 private PesiExportMapping
getPureNameMapping() {
2216 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2218 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2220 // mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2222 mapping
.addMapper(MethodMapper
.NewInstance("KingdomFk", this, TaxonNameBase
.class));
2223 mapping
.addMapper(MethodMapper
.NewInstance("RankFk", this, TaxonNameBase
.class));
2224 mapping
.addMapper(MethodMapper
.NewInstance("RankCache", this, TaxonNameBase
.class));
2225 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusFk", Types
.INTEGER
, PesiTransformer
.T_STATUS_UNACCEPTED
));
2226 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusCache", Types
.VARCHAR
, PesiTransformer
.T_STATUS_STR_UNACCEPTED
));
2227 mapping
.addMapper(DbStringMapper
.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
2228 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this, TaxonNameBase
.class));
2231 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2232 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2234 addNameMappers(mapping
);
2235 //TODO add author mapper, TypeNameFk
2240 private void addNameMappers(PesiExportMapping mapping
) {
2241 ExtensionType extensionType
;
2242 mapping
.addMapper(DbStringMapper
.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2243 mapping
.addMapper(DbStringMapper
.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2244 mapping
.addMapper(DbStringMapper
.NewInstance("SpecificEpithet", "SpecificEpithet"));
2245 mapping
.addMapper(DbStringMapper
.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2247 // mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName")); //does not work as we need other cache strategy
2248 mapping
.addMapper(MethodMapper
.NewInstance("WebSearchName", this, TaxonNameBase
.class));
2250 // mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName")); //does not work as we need other cache strategy
2251 mapping
.addMapper(MethodMapper
.NewInstance("FullName", this, TaxonNameBase
.class));
2254 mapping
.addMapper(MethodMapper
.NewInstance("NomRefString", this, TaxonNameBase
.class));
2257 extensionType
= (ExtensionType
)getTermService().find(ErmsTransformer
.uuidDisplayName
);
2258 if (extensionType
!= null) {
2259 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionType
, "DisplayName"));
2261 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this, TaxonNameBase
.class));
2264 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusFk", this, TaxonNameBase
.class));
2265 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusCache", this, TaxonNameBase
.class, PesiExportState
.class));
2266 mapping
.addMapper(MethodMapper
.NewInstance("TypeFullnameCache", this, TaxonNameBase
.class));
2268 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusFk", this, TaxonNameBase
.class));
2269 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusCache", this, TaxonNameBase
.class, PesiExportState
.class));
2272 // FossilStatus (Fk, Cache)
2273 extensionType
= (ExtensionType
)getTermService().find(ErmsTransformer
.uuidFossilStatus
);
2274 if (extensionType
!= null) {
2275 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionType
, "FossilStatusCache"));
2277 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusCache", this, TaxonNameBase
.class));
2279 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusFk", this, TaxonNameBase
.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2281 mapping
.addMapper(MethodMapper
.NewInstance("IdInSource", this, IdentifiableEntity
.class));
2282 mapping
.addMapper(MethodMapper
.NewInstance("OriginalDB", this, IdentifiableEntity
.class) );
2284 //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());