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 com
.yourkit
.api
.Controller
;
36 import eu
.etaxonomy
.cdm
.api
.service
.TaxonServiceImpl
;
37 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
38 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
39 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
40 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbConstantMapper
;
41 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbExtensionMapper
;
42 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbLastActionMapper
;
43 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbObjectMapper
;
44 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.DbStringMapper
;
45 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.IdMapper
;
46 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.MethodMapper
;
47 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.out
.ObjectChangeMapper
;
48 import eu
.etaxonomy
.cdm
.io
.pesi
.erms
.ErmsTransformer
;
49 import eu
.etaxonomy
.cdm
.io
.profiler
.ProfilerController
;
50 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
51 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
52 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
53 import eu
.etaxonomy
.cdm
.model
.common
.Extension
;
54 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
55 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
56 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
57 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
58 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
59 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
60 import eu
.etaxonomy
.cdm
.model
.common
.RelationshipBase
;
61 import eu
.etaxonomy
.cdm
.model
.name
.BacterialName
;
62 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
63 import eu
.etaxonomy
.cdm
.model
.name
.HybridRelationship
;
64 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationship
;
65 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignation
;
66 import eu
.etaxonomy
.cdm
.model
.name
.NameTypeDesignationStatus
;
67 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
68 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
69 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
70 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
71 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
72 import eu
.etaxonomy
.cdm
.model
.name
.ZoologicalName
;
73 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
74 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
75 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
76 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
77 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationship
;
78 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymRelationshipType
;
79 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
80 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
81 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
82 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationship
;
83 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
84 import eu
.etaxonomy
.cdm
.strategy
.cache
.HTMLTagRules
;
85 import eu
.etaxonomy
.cdm
.strategy
.cache
.TagEnum
;
86 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.BacterialNameDefaultCacheStrategy
;
87 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.BotanicNameDefaultCacheStrategy
;
88 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.INonViralNameCacheStrategy
;
89 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.NonViralNameDefaultCacheStrategy
;
90 import eu
.etaxonomy
.cdm
.strategy
.cache
.name
.ZooNameNoMarkerCacheStrategy
;
93 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
94 * Inserts into DataWarehouse database table <code>Taxon</code>.
95 * It is divided into four phases:<p><ul>
96 * <li>Phase 1: Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.
97 * <li>Phase 2: Export of additional data: ParenTaxonFk and TreeIndex.
98 * <li>Phase 3: Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
99 * <li>Phase 4: Export of Inferred Synonyms.</ul>
105 public class PesiTaxonExport
extends PesiExportBase
{
106 private static final Logger logger
= Logger
.getLogger(PesiTaxonExport
.class);
107 private static final Class
<?
extends CdmBase
> standardMethodParameter
= TaxonBase
.class;
109 private static int modCount
= 1000;
110 private static final String dbTableName
= "Taxon";
111 private static final String dbTableNameSynRel
= "RelTaxon";
112 private static final String pluralString
= "Taxa";
113 private static final String parentPluralString
= "Taxa";
114 private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt
;
115 private PreparedStatement rankTypeExpertsUpdateStmt
;
116 private PreparedStatement rankUpdateStmt
;
117 private NomenclaturalCode nomenclaturalCode
;
118 private Integer kingdomFk
;
119 private HashMap
<Rank
, Rank
> rank2endRankMap
= new HashMap
<Rank
, Rank
>();
120 private List
<Rank
> rankList
= new ArrayList
<Rank
>();
121 private static final UUID uuidTreeIndex
= UUID
.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");
122 private AnnotationType treeIndexAnnotationType
;
123 private static ExtensionType lastActionExtensionType
;
124 private static ExtensionType lastActionDateExtensionType
;
125 private static ExtensionType expertNameExtensionType
;
126 private static ExtensionType speciesExpertNameExtensionType
;
127 private static ExtensionType cacheCitationExtensionType
;
128 public static NonViralNameDefaultCacheStrategy
<?
> zooNameStrategy
= ZooNameNoMarkerCacheStrategy
.NewInstance();
129 public static NonViralNameDefaultCacheStrategy
<?
> botanicalNameStrategy
= BotanicNameDefaultCacheStrategy
.NewInstance();
130 public static NonViralNameDefaultCacheStrategy
<?
> nonViralNameStrategy
= NonViralNameDefaultCacheStrategy
.NewInstance();
131 public static NonViralNameDefaultCacheStrategy
<?
> bacterialNameStrategy
= BacterialNameDefaultCacheStrategy
.NewInstance();
132 private static int currentTaxonId
;
136 * @return the treeIndexAnnotationType
138 protected AnnotationType
getTreeIndexAnnotationType() {
139 return treeIndexAnnotationType
;
143 * @param treeIndexAnnotationType the treeIndexAnnotationType to set
145 protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType
) {
146 this.treeIndexAnnotationType
= treeIndexAnnotationType
;
157 public PesiTaxonExport() {
162 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
165 public Class
<?
extends CdmBase
> getStandardMethodParameter() {
166 return standardMethodParameter
;
170 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
173 protected boolean doCheck(PesiExportState state
) {
174 boolean result
= true;
180 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
183 protected void doInvoke(PesiExportState state
) {
185 logger
.info("*** Started Making " + pluralString
+ " ...");
187 initPreparedStatements(state
);
189 // Stores whether this invoke was successful or not.
190 boolean success
= true;
192 // PESI: Clear the database table Taxon.
195 // Get specific mappings: (CDM) Taxon -> (PESI) Taxon
196 PesiExportMapping mapping
= getMapping();
197 PesiExportMapping synonymRelMapping
= getSynRelMapping();
199 // Initialize the db mapper
200 mapping
.initialize(state
);
201 synonymRelMapping
.initialize(state
);
202 // Find extensionTypes
203 lastActionExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.lastActionUuid
);
204 lastActionDateExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.lastActionDateUuid
);
205 expertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.expertNameUuid
);
206 speciesExpertNameExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.speciesExpertNameUuid
);
207 cacheCitationExtensionType
= (ExtensionType
)getTermService().find(PesiTransformer
.cacheCitationUuid
);
210 success
&= doPhase01(state
, mapping
);
212 //"PHASE 1b: Handle names without taxa ...
213 success
&= doNames(state
);
216 // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
217 success
&= doPhase02(state
);
219 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
220 success
&= doPhase03(state
);
223 //"PHASE 4: Creating Inferred Synonyms...
224 success
&= doPhase04(state
, mapping
, synonymRelMapping
);
226 //updates to TaxonStatus and others
227 success
&= doPhaseUpdates(state
);
230 logger
.info("*** Finished Making " + pluralString
+ " ..." + getSuccessString(success
));
233 state
.setUnsuccessfull();
236 } catch (SQLException e
) {
238 logger
.error(e
.getMessage());
239 state
.setUnsuccessfull();
245 //TODO check if this can all be done by getTaxonStatus
246 private boolean doPhaseUpdates(PesiExportState state
) {
249 String oldStatusFilter
= "= 7 "; //"= '" + PesiTransformer.T_STATUS_STR_UNACCEPTED + "' ";
250 String emStr
= PesiTransformer
.SOURCE_STR_EM
;
251 String feStr
= PesiTransformer
.SOURCE_STR_FE
;
252 String ifStr
= PesiTransformer
.SOURCE_STR_IF
;
255 String updateNotAccepted
= " UPDATE Taxon SET TaxonStatusFk = %d, TaxonStatusCache = '%s' " +
256 " WHERE OriginalDB = '%s' AND taxonstatusfk = 1 AND ParentTaxonFk %s AND RankFk > 180 ";
257 updateNotAccepted
= String
.format(updateNotAccepted
, 8, "NOT ACCEPTED: TAXONOMICALLY VALUELESS LOCAL OR SINGULAR BIOTYPE", emStr
, oldStatusFilter
);
258 int updated
= state
.getConfig().getDestination().update(updateNotAccepted
);
261 String updateAlternativeName
= "UPDATE Taxon SET TaxonStatusFk = 1, TaxonStatusCache = 'accepted' " +
262 " FROM RelTaxon RIGHT OUTER JOIN Taxon ON RelTaxon.TaxonFk1 = Taxon.TaxonId " +
263 " WHERE (RelTaxon.RelTaxonQualifierFk = 17) AND (Taxon.TaxonStatusFk %s) ";
264 updateAlternativeName
= String
.format(updateAlternativeName
, oldStatusFilter
);
265 updated
= state
.getConfig().getDestination().update(updateAlternativeName
);
267 String updateSynonyms
= " UPDATE Taxon SET TaxonStatusFk = 2, TaxonStatusCache = 'synonym' " +
268 " FROM RelTaxon RIGHT OUTER JOIN Taxon ON RelTaxon.TaxonFk1 = Taxon.TaxonId " +
269 " WHERE (RelTaxon.RelTaxonQualifierFk in (1, 3)) AND (Taxon.TaxonStatusFk %S)";
270 updateSynonyms
= String
.format(updateSynonyms
, oldStatusFilter
);
271 updated
= state
.getConfig().getDestination().update(updateSynonyms
);
273 // cache citation - check if this can't be done in getCacheCitation
274 // cache citation - FE
275 // String updateCacheCitationFE = " UPDATE Taxon " +
276 // " SET CacheCitation = IsNull(SpeciesExpertName + '. ', '') + WebShowName + '. Accessed through: Fauna Europaea at http://www.faunaeur.org/full_results.php?id=' + cast(TempFE_Id as varchar) " +
277 // " WHERE OriginalDb = '%s'";
278 // updateCacheCitationFE = String.format(updateCacheCitationFE, feStr);
279 // updated = state.getConfig().getDestination().update(updateCacheCitationFE);
281 // cache citation - EM
282 String updateCacheCitationEM
= " UPDATE Taxon " +
283 " SET CacheCitation = SpeciesExpertName + ' ' + WebShowName + '. Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=' + GUID " +
284 " WHERE OriginalDb = '%s'";
285 updateCacheCitationEM
= String
.format(updateCacheCitationEM
, emStr
);
286 updated
= state
.getConfig().getDestination().update(updateCacheCitationEM
);
288 // cache citation - IF
289 // String updateCacheCitationIF = " UPDATE Taxon " +
290 // " SET CacheCitation = IsNull(SpeciesExpertName + ' ', '') + WebShowName + '. Accessed through: Index Fungorum at http://www.indexfungorum.org/names/NamesRecord.asp?RecordID=' + cast(TempIF_Id as varchar) " +
291 // " WHERE OriginalDb = '%s'";
292 // updateCacheCitationIF = String.format(updateCacheCitationIF, ifStr);
293 // updated = state.getConfig().getDestination().update(updateCacheCitationIF);
298 private void initPreparedStatements(PesiExportState state
) throws SQLException
{
299 initTreeIndexStatement(state
);
300 initRankExpertsUpdateStmt(state
);
301 initRankUpdateStatement(state
);
304 // Prepare TreeIndex-And-KingdomFk-Statement
305 private void initTreeIndexStatement(PesiExportState state
) throws SQLException
{
306 Connection connection
= state
.getConfig().getDestination().getConnection();
307 String parentTaxonFk_TreeIndex_KingdomFkSql
= "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?";
308 parentTaxonFk_TreeIndex_KingdomFkStmt
= connection
.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql
);
311 private void initRankUpdateStatement(PesiExportState state
) throws SQLException
{
312 Connection connection
= state
.getConfig().getDestination().getConnection();
313 String rankSql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
314 rankUpdateStmt
= connection
.prepareStatement(rankSql
);
317 private void initRankExpertsUpdateStmt(PesiExportState state
) throws SQLException
{
318 // String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
319 // "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
320 //TODO handle experts GUIDs
321 Connection connection
= state
.getConfig().getDestination().getConnection();
323 String sql
= "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
324 " WHERE TaxonId = ?";
325 rankTypeExpertsUpdateStmt
= connection
.prepareStatement(sql
);
328 private boolean doPhase01(PesiExportState state
, PesiExportMapping mapping
) throws SQLException
{
331 List
<TaxonBase
> list
;
332 boolean success
= true;
333 // Get the limit for objects to save within a single transaction.
334 int limit
= state
.getConfig().getLimitSave();
337 logger
.info("PHASE 1: Export Taxa...limit is " + limit
);
339 TransactionStatus txStatus
= startTransaction(true);
340 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
344 int partitionCount
= 0;
346 logger
.warn("Taking snapshot at the beginning of phase 1 of taxonExport");
347 ProfilerController
.memorySnapshot();
348 while ((list
= getNextTaxonPartition(null, limit
, partitionCount
++, null)) != null ) {
350 logger
.info("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
351 for (TaxonBase
<?
> taxon
: list
) {
352 doCount(count
++, modCount
, pluralString
);
353 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
354 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
356 if (! nvn
.isProtectedTitleCache()){
357 nvn
.setTitleCache(null, false);
359 if (! nvn
.isProtectedNameCache()){
360 nvn
.setNameCache(null, false);
362 if (! nvn
.isProtectedFullTitleCache()){
363 nvn
.setFullTitleCache(null, false);
365 if (! nvn
.isProtectedAuthorshipCache()){
366 nvn
.setAuthorshipCache(null, false);
369 success
&= mapping
.invoke(taxon
);
371 validatePhaseOne(taxon
, nvn
);
381 // Commit transaction
382 commitTransaction(txStatus
);
383 logger
.debug("Committed transaction.");
384 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
386 /*logger.warn("Taking snapshot at the end of the loop of phase 1 of taxonExport");
387 ProfilerController.memorySnapshot();
390 txStatus
= startTransaction(true);
391 logger
.info("Started new transaction. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
395 logger
.info("No " + pluralString
+ " left to fetch.");
400 // Commit transaction
401 commitTransaction(txStatus
);
403 logger
.debug("Committed transaction.");
405 logger
.warn("Taking snapshot at the end of phase 1 of taxonExport");
406 ProfilerController
.memorySnapshot();
411 private void validatePhaseOne(TaxonBase
<?
> taxon
, NonViralName taxonName
) {
412 // Check whether some rules are violated
413 nomenclaturalCode
= taxonName
.getNomenclaturalCode();
414 String genusOrUninomial
= taxonName
.getGenusOrUninomial();
415 String specificEpithet
= taxonName
.getSpecificEpithet();
416 String infraSpecificEpithet
= taxonName
.getInfraSpecificEpithet();
417 String infraGenericEpithet
= taxonName
.getInfraGenericEpithet();
418 Integer rank
= getRankFk(taxonName
, nomenclaturalCode
);
421 logger
.error("Rank was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
424 // Check whether infraGenericEpithet is set correctly
425 // 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
426 // 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
428 int ancestorLevel
= 0;
429 if (taxonName
.getRank().equals(Rank
.SUBSPECIES())) {
430 // The accepted taxon two rank levels above should be of rank subgenus
433 if (taxonName
.getRank().equals(Rank
.SPECIES())) {
434 // The accepted taxon one rank level above should be of rank subgenus
437 if (ancestorLevel
> 0) {
438 if (validateAncestorOfSpecificRank(taxon
, ancestorLevel
, Rank
.SUBGENUS())) {
439 // The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
440 if (infraGenericEpithet
== null) {
441 logger
.warn("InfraGenericEpithet does not exist even though it should for: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
442 // maybe the taxon could be named here
447 if (infraGenericEpithet
== null && rank
.intValue() == 190) {
448 logger
.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
450 if (specificEpithet
!= null && rank
.intValue() < 216) {
451 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() + ")");
453 if (infraSpecificEpithet
!= null && rank
.intValue() < 225) {
454 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() + ")";
455 if (StringUtils
.isNotBlank(infraSpecificEpithet
)){
456 logger
.warn(message
);
458 logger
.warn(message
);
462 if (infraSpecificEpithet
!= null && specificEpithet
== null) {
463 logger
.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
465 if (genusOrUninomial
== null) {
466 logger
.warn("GenusOrUninomial was not determined: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
470 // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
471 private boolean doPhase02(PesiExportState state
) {
472 boolean success
= true;
473 if (! state
.getConfig().isDoTreeIndex()){
474 logger
.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
478 List
<Classification
> classificationList
= null;
479 logger
.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
481 // Specify starting ranks for tree traversing
482 rankList
.add(Rank
.KINGDOM());
483 rankList
.add(Rank
.GENUS());
485 // Specify where to stop traversing (value) when starting at a specific Rank (key)
486 rank2endRankMap
.put(Rank
.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
487 rank2endRankMap
.put(Rank
.KINGDOM(), Rank
.GENUS()); // excludes rank genus
489 StringBuffer treeIndex
= new StringBuffer();
491 // Retrieve list of classifications
492 TransactionStatus txStatus
= startTransaction(true);
493 logger
.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
494 classificationList
= getClassificationService().listClassifications(null, 0, null, null);
495 commitTransaction(txStatus
);
496 logger
.debug("Committed transaction.");
498 logger
.info("Fetched " + classificationList
.size() + " classification(s).");
500 setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex
, "TreeIndex", "TreeIndex", "TI"));
501 List
<TaxonNode
> rankSpecificRootNodes
;
502 for (Classification classification
: classificationList
) {
503 for (Rank rank
: rankList
) {
505 txStatus
= startTransaction(true);
506 logger
.info("Started transaction to fetch all rootNodes specific to Rank " + rank
.getLabel() + " ...");
508 rankSpecificRootNodes
= getClassificationService().loadRankSpecificRootNodes(classification
, rank
, null);
509 logger
.info("Fetched " + rankSpecificRootNodes
.size() + " RootNodes for Rank " + rank
.getLabel());
511 commitTransaction(txStatus
);
512 logger
.debug("Committed transaction.");
514 for (TaxonNode rootNode
: rankSpecificRootNodes
) {
515 txStatus
= startTransaction(false);
516 Rank endRank
= rank2endRankMap
.get(rank
);
517 if (endRank
!= null) {
518 logger
.debug("Started transaction to traverse childNodes of rootNode (" + rootNode
.getUuid() + ") till Rank " + endRank
.getLabel() + " ...");
520 logger
.debug("Started transaction to traverse childNodes of rootNode (" + rootNode
.getUuid() + ") till leaves are reached ...");
523 TaxonNode newNode
= getTaxonNodeService().load(rootNode
.getUuid());
525 if (isPesiTaxon(newNode
.getTaxon())){
526 TaxonNode parentNode
= newNode
.getParent();
527 if (rank
.equals(Rank
.KINGDOM())) {
528 treeIndex
= new StringBuffer();
529 treeIndex
.append("#");
531 // Get treeIndex from parentNode
532 if (parentNode
!= null) {
533 boolean annotationFound
= false;
534 Set
<Annotation
> annotations
= parentNode
.getAnnotations();
535 for (Annotation annotation
: annotations
) {
536 AnnotationType annotationType
= annotation
.getAnnotationType();
537 if (annotationType
!= null && annotationType
.equals(getTreeIndexAnnotationType())) {
538 treeIndex
= new StringBuffer(CdmUtils
.Nz(annotation
.getText()));
539 annotationFound
= true;
540 // logger.error("treeIndex: " + treeIndex);
544 if (!annotationFound
) {
545 // This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
546 logger
.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode
.getUuid() + ", Taxon: " + parentNode
.getTaxon().getUuid());
547 treeIndex
= new StringBuffer();
548 treeIndex
.append("#");
551 // TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
552 logger
.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode
.getUuid());
553 treeIndex
= new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
554 treeIndex
.append("#");
557 nomenclaturalCode
= newNode
.getTaxon().getName().getNomenclaturalCode();
558 kingdomFk
= PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
);
559 traverseTree(newNode
, parentNode
, treeIndex
, endRank
, state
);
562 logger
.debug("Taxon is not a PESI taxon: " + newNode
.getTaxon().getUuid());
568 commitTransaction(txStatus
);
569 logger
.debug("Committed transaction.");
570 } catch (Exception e
) {
571 logger
.error(e
.getMessage());
576 rankSpecificRootNodes
= null;
581 logger
.warn("Taking snapshot at the end of phase 2 of taxonExport");
582 ProfilerController
.memorySnapshot();
586 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
587 private boolean doPhase03(PesiExportState state
) {
590 boolean success
= true;
591 if (! state
.getConfig().isDoTreeIndex()){
592 logger
.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
595 // Get the limit for objects to save within a single transaction.
596 int limit
= state
.getConfig().getLimitSave();
598 List
<TaxonBase
> list
;
599 logger
.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
600 // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
603 TransactionStatus txStatus
= startTransaction(true);
604 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
605 int partitionCount
= 0;
606 while ((list
= getNextTaxonPartition(TaxonBase
.class, limit
, partitionCount
++, null)) != null) {
608 logger
.info("Fetched " + list
.size() + " " + pluralString
+ ". Exporting...");
609 for (TaxonBase
<?
> taxon
: list
) {
610 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
611 // Determine expertFk
612 // Integer expertFk = makeExpertFk(state, taxonName);
614 // // Determine speciesExpertFk
615 // Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
617 doCount(count
++, modCount
, pluralString
);
618 Integer typeNameFk
= getTypeNameFk(taxonName
, state
);
620 //TODO why are expertFks needed? (Andreas M.)
621 // if (expertFk != null || speciesExpertFk != null) {
622 invokeRankDataAndTypeNameFkAndKingdomFk(taxonName
, nomenclaturalCode
, state
.getDbId(taxon
),
623 typeNameFk
, kingdomFk
);
630 // Commit transaction
631 commitTransaction(txStatus
);
632 logger
.debug("Committed transaction.");
633 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
637 txStatus
= startTransaction(true);
638 logger
.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
641 logger
.info("No " + pluralString
+ " left to fetch.");
646 // Commit transaction
647 commitTransaction(txStatus
);
649 logger
.debug("Committed transaction.");
650 logger
.warn("Taking snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount
);
651 ProfilerController
.memorySnapshot();
655 // "PHASE 4: Creating Inferred Synonyms..."
656 private boolean doPhase04(PesiExportState state
, PesiExportMapping mapping
, PesiExportMapping synRelMapping
) throws SQLException
{
659 boolean success
= true;
660 // Get the limit for objects to save within a single transaction.
661 if (! state
.getConfig().isDoInferredSynonyms()){
662 logger
.info ("Ignore PHASE 4: Creating Inferred Synonyms...");
666 int limit
= state
.getConfig().getLimitSave();
667 // Create inferred synonyms for accepted taxa
668 logger
.info("PHASE 4: Creating Inferred Synonyms...");
670 // Determine the count of elements in datawarehouse database table Taxon
671 currentTaxonId
= determineTaxonCount(state
);
676 int pageSize
= limit
;
678 String inferredSynonymPluralString
= "Inferred Synonyms";
681 TransactionStatus txStatus
= startTransaction(true);
682 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
683 List
<TaxonBase
> taxonList
= null;
687 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", Rank
.SPECIES(), pageSize
, pageNumber
)).size() > 0) {
688 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
690 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
691 inferredSynonymsDataToBeSaved
.putAll(createInferredSynonymsForTaxonList(state
, mapping
,
692 synRelMapping
, taxonList
));
694 doCount(count
+= taxonList
.size(), modCount
, inferredSynonymPluralString
);
695 // Commit transaction
696 commitTransaction(txStatus
);
697 logger
.debug("Committed transaction.");
698 logger
.info("Exported " + (taxonList
.size()) + " " + 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
714 while ((taxonList
= getTaxonService().listTaxaByName(Taxon
.class, "*", "*", "*", "*", Rank
.SUBSPECIES(), pageSize
, pageNumber
)).size() > 0) {
715 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
717 logger
.info("Fetched " + taxonList
.size() + " " + parentPluralString
+ ". Exporting...");
718 inferredSynonymsDataToBeSaved
.putAll(createInferredSynonymsForTaxonList(state
, mapping
,
719 synRelMapping
, taxonList
));
721 doCount(count
+= taxonList
.size(), modCount
, inferredSynonymPluralString
);
722 // Commit transaction
723 commitTransaction(txStatus
);
724 logger
.debug("Committed transaction.");
725 logger
.info("Exported " + taxonList
.size()+ " " + inferredSynonymPluralString
+ ". Total: " + count
);
728 // Save Rank Data and KingdomFk for inferred synonyms
729 for (Integer taxonFk
: inferredSynonymsDataToBeSaved
.keySet()) {
730 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved
.get(taxonFk
), nomenclaturalCode
, taxonFk
, kingdomFk
);
734 txStatus
= startTransaction(true);
735 logger
.info("Started new transaction. Fetching some " + parentPluralString
+ " first (max: " + limit
+ ") ...");
737 // Increment pageNumber
740 if (taxonList
.size() == 0) {
741 logger
.info("No " + parentPluralString
+ " left to fetch.");
745 logger
.warn("Taking snapshot at the end of phase 4 of taxonExport");
746 ProfilerController
.memorySnapshot();
748 // Commit transaction
749 commitTransaction(txStatus
);
750 logger
.warn("Taking snapshot at the end of phase 4 after commit of taxonExport");
751 ProfilerController
.memorySnapshot();
753 logger
.warn("Taking snapshot at the end of phase 4 after gc() of taxonExport");
754 ProfilerController
.memorySnapshot();
755 logger
.debug("Committed transaction.");
762 * @param synRelMapping
763 * @param currentTaxonId
765 * @param inferredSynonymsDataToBeSaved
768 private HashMap
<Integer
, TaxonNameBase
<?
, ?
>> createInferredSynonymsForTaxonList(PesiExportState state
,
769 PesiExportMapping mapping
, PesiExportMapping synRelMapping
,
770 List
<TaxonBase
> taxonList
) {
773 Classification classification
= null;
774 List
<Synonym
> inferredSynonyms
= null;
775 boolean localSuccess
= true;
777 HashMap
<Integer
, TaxonNameBase
<?
,?
>> inferredSynonymsDataToBeSaved
= new HashMap
<Integer
, TaxonNameBase
<?
,?
>>();
779 for (TaxonBase
<?
> taxonBase
: taxonList
) {
781 if (taxonBase
.isInstanceOf(Taxon
.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
782 acceptedTaxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
783 TaxonNameBase
<?
,?
> taxonName
= acceptedTaxon
.getName();
785 if (taxonName
.isInstanceOf(ZoologicalName
.class)) {
786 nomenclaturalCode
= taxonName
.getNomenclaturalCode();
787 kingdomFk
= PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
);
789 Set
<TaxonNode
> taxonNodes
= acceptedTaxon
.getTaxonNodes();
790 TaxonNode singleNode
= null;
792 if (taxonNodes
.size() > 0) {
793 // Determine the classification of the current TaxonNode
795 singleNode
= taxonNodes
.iterator().next();
796 if (singleNode
!= null) {
797 classification
= singleNode
.getClassification();
799 logger
.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() +")");
802 // Classification could not be determined directly from this TaxonNode
803 // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
804 if (taxonNodes
.size() == 0) {
805 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");
810 if (classification
!= null) {
812 TaxonNameBase name
= acceptedTaxon
.getName();
813 //if (name.isSpecies() || name.isInfraSpecific()){
814 inferredSynonyms
= getTaxonService().createAllInferredSynonyms(acceptedTaxon
, classification
, true);
816 // inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
817 if (inferredSynonyms
!= null) {
818 for (Synonym synonym
: inferredSynonyms
) {
819 // TaxonNameBase<?,?> synonymName = synonym.getName();
820 MarkerType markerType
=getUuidMarkerType(PesiTransformer
.uuidMarkerGuidIsMissing
, state
);
821 synonym
.addMarker(Marker
.NewInstance(markerType
, true));
822 // Both Synonym and its TaxonName have no valid Id yet
823 synonym
.setId(currentTaxonId
++);
826 localSuccess
&= mapping
.invoke(synonym
);
827 //get SynonymRelationship and export
828 if (synonym
.getSynonymRelations().isEmpty() ){
829 SynonymRelationship synRel
;
830 IdentifiableSource source
= synonym
.getSources().iterator().next();
831 if (source
.getIdNamespace().contains("Potential combination")){
832 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.POTENTIAL_COMBINATION_OF());
833 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to potential combination");
834 } else if (source
.getIdNamespace().contains("Inferred Genus")){
835 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.INFERRED_GENUS_OF());
836 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to inferred genus");
837 } else if (source
.getIdNamespace().contains("Inferred Epithet")){
838 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.INFERRED_EPITHET_OF());
839 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to inferred epithet");
841 synRel
= acceptedTaxon
.addSynonym(synonym
, SynonymRelationshipType
.INFERRED_SYNONYM_OF());
842 logger
.warn(synonym
.getTitleCache() + " has no synonym relationship to " + acceptedTaxon
.getTitleCache() + " type is set to inferred synonym");
845 localSuccess
&= synRelMapping
.invoke(synRel
);
847 logger
.warn("Synonym relationship export failed " + synonym
.getTitleCache() + " accepted taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
851 for (SynonymRelationship synRel
: synonym
.getSynonymRelations()){
852 localSuccess
&= synRelMapping
.invoke(synRel
);
854 logger
.warn("Synonym relationship export failed " + synonym
.getTitleCache() + " accepted taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache()+")");
860 inferredSynonymsDataToBeSaved
.put(synonym
.getId(), synonym
.getName());
864 logger
.error(e
.getMessage());
868 logger
.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon
.getUuid() + " (" + acceptedTaxon
.getTitleCache() + ")");
871 // logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
874 logger
.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase
.getUuid() + " (" + taxonBase
.getTitleCache() + ")");
877 return inferredSynonymsDataToBeSaved
;
882 * Handles names that do not appear in taxa
887 private boolean doNames(PesiExportState state
) throws SQLException
{
889 boolean success
= true;
890 if (! state
.getConfig().isDoPureNames()){
891 logger
.info ("Ignore PHASE 1b: PureNames");
896 PesiExportMapping mapping
= getPureNameMapping();
897 mapping
.initialize(state
);
900 List
<NonViralName
<?
>> list
;
902 // Get the limit for objects to save within a single transaction.
903 int limit
= state
.getConfig().getLimitSave();
906 logger
.info("PHASE 1b: Export Pure Names ...");
908 TransactionStatus txStatus
= startTransaction(true);
909 logger
.info("Started new transaction for Pure Names. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
912 int partitionCount
= 0;
913 while ((list
= getNextPureNamePartition(null, limit
, partitionCount
++)) != null ) {
915 logger
.info("Fetched " + list
.size() + " names without taxa. Exporting...");
916 for (TaxonNameBase taxonName
: list
) {
917 doCount(count
++, modCount
, pluralString
);
918 success
&= mapping
.invoke(taxonName
);
921 // Commit transaction
922 commitTransaction(txStatus
);
923 logger
.debug("Committed transaction.");
924 logger
.info("Exported " + (count
- pastCount
) + " " + pluralString
+ ". Total: " + count
);
928 txStatus
= startTransaction(true);
929 logger
.info("Started new transaction for PureNames. Fetching some " + pluralString
+ " (max: " + limit
+ ") ...");
932 logger
.info("No " + pluralString
+ " left to fetch.");
934 // Commit transaction
935 commitTransaction(txStatus
);
936 logger
.debug("Committed transaction.");
937 } catch (Exception e
) {
938 logger
.error("Error occurred in pure name export");
946 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
947 * @param state The {@link PesiExportState PesiExportState}.
950 private Integer
determineTaxonCount(PesiExportState state
) {
951 Integer result
= null;
952 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
955 Source destination
= pesiConfig
.getDestination();
956 sql
= "SELECT max(taxonId) FROM Taxon";
957 destination
.setQuery(sql
);
958 ResultSet resultSet
= destination
.getResultSet();
961 result
= resultSet
.getInt(1);
962 } catch (SQLException e
) {
963 logger
.error("TaxonCount could not be determined: " + e
.getMessage());
970 * Checks whether a parent at specific level has a specific Rank.
971 * @param taxonName A {@link TaxonNameBase TaxonName}.
972 * @param level The ancestor level.
973 * @param ancestorRank The ancestor rank.
974 * @return Whether a parent at a specific level has a specific Rank.
976 private boolean validateAncestorOfSpecificRank(TaxonBase
<?
> taxonBase
, int level
, Rank ancestorRank
) {
977 boolean result
= false;
978 TaxonNode parentNode
= null;
979 if (taxonBase
.isInstanceOf(Taxon
.class)){
980 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
981 // Get ancestor Taxon via TaxonNode
982 Set
<TaxonNode
> taxonNodes
= taxon
.getTaxonNodes();
983 if (taxonNodes
.size() == 1) {
984 TaxonNode taxonNode
= taxonNodes
.iterator().next();
985 if (taxonNode
!= null) {
986 for (int i
= 0; i
< level
; i
++) {
987 if (taxonNode
!= null) {
988 taxonNode
= taxonNode
.getParent();
991 parentNode
= taxonNode
;
993 } else if (taxonNodes
.size() > 1) {
994 logger
.error("This taxon has " + taxonNodes
.size() + " taxonNodes: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
998 if (parentNode
!= null) {
999 TaxonNode node
= CdmBase
.deproxy(parentNode
, TaxonNode
.class);
1000 Taxon parentTaxon
= node
.getTaxon();
1001 if (parentTaxon
!= null) {
1002 TaxonNameBase
<?
,?
> parentTaxonName
= parentTaxon
.getName();
1003 if (parentTaxonName
!= null && parentTaxonName
.getRank().equals(ancestorRank
)) {
1007 logger
.error("This TaxonNode has no Taxon: " + node
.getUuid());
1014 * Returns the AnnotationType for a given UUID.
1015 * @param uuid The Annotation UUID.
1016 * @param label The Annotation label.
1017 * @param text The Annotation text.
1018 * @param labelAbbrev The Annotation label abbreviation.
1019 * @return The AnnotationType.
1021 protected AnnotationType
getAnnotationType(UUID uuid
, String label
, String text
, String labelAbbrev
){
1022 AnnotationType annotationType
= (AnnotationType
)getTermService().find(uuid
);
1023 if (annotationType
== null) {
1024 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
1025 annotationType
.setUuid(uuid
);
1026 // annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1027 getTermService().save(annotationType
);
1029 return annotationType
;
1033 * Traverses the classification recursively and stores determined values for every Taxon.
1034 * @param childNode The {@link TaxonNode TaxonNode} to process.
1035 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1036 * @param treeIndex The TreeIndex at the current level.
1037 * @param fetchLevel Rank to stop fetching at.
1038 * @param state The {@link PesiExportState PesiExportState}.
1040 private void traverseTree(TaxonNode childNode
, TaxonNode parentNode
, StringBuffer treeIndex
, Rank fetchLevel
, PesiExportState state
) {
1041 // Traverse all branches from this childNode until specified fetchLevel is reached.
1042 StringBuffer localTreeIndex
= new StringBuffer(treeIndex
);
1043 Taxon childTaxon
= childNode
.getTaxon();
1044 if (childTaxon
!= null) {
1045 if (isPesiTaxon(childTaxon
)){
1046 Integer taxonId
= state
.getDbId(childTaxon
);
1047 TaxonNameBase
<?
,?
> childName
= childTaxon
.getName();
1048 if (taxonId
!= null) {
1049 Rank childRank
= childName
.getRank();
1050 if (childRank
!= null) {
1051 if (! childRank
.equals(fetchLevel
)) {
1053 localTreeIndex
.append(taxonId
+ "#");
1055 saveData(childNode
, parentNode
, localTreeIndex
, state
, taxonId
);
1057 // Store treeIndex as annotation for further use
1058 Annotation annotation
= Annotation
.NewInstance(localTreeIndex
.toString(), getTreeIndexAnnotationType(), Language
.DEFAULT());
1059 childNode
.addAnnotation(annotation
);
1061 for (TaxonNode newNode
: childNode
.getChildNodes()) {
1062 if (newNode
.getTaxon() != null && isPesiTaxon(newNode
.getTaxon())){
1063 traverseTree(newNode
, childNode
, localTreeIndex
, fetchLevel
, state
);
1068 // logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1072 logger
.error("Rank is NULL. FetchLevel can not be checked: " + childName
.getUuid() + " (" + childName
.getTitleCache() + ")");
1075 logger
.error("Taxon can not be found in state: " + childTaxon
.getUuid() + " (" + childTaxon
.getTitleCache() + ")");
1078 if (logger
.isDebugEnabled()){
1079 logger
.debug("Taxon is not a PESI taxon: " + childTaxon
.getUuid());
1084 logger
.error("Taxon is NULL for TaxonNode: " + childNode
.getUuid());
1089 * Stores values in database for every recursive round.
1090 * @param childNode The {@link TaxonNode TaxonNode} to process.
1091 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1092 * @param treeIndex The TreeIndex at the current level.
1093 * @param state The {@link PesiExportState PesiExportState}.
1094 * @param currentTaxonFk The TaxonFk to store the values for.
1096 private void saveData(TaxonNode childNode
, TaxonNode parentNode
, StringBuffer treeIndex
, PesiExportState state
, Integer currentTaxonFk
) {
1097 // We are differentiating kingdoms by the nomenclatural code for now.
1098 // This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1099 Taxon childTaxon
= childNode
.getTaxon();
1100 if (isPesiTaxon(childTaxon
)) {
1101 TaxonBase
<?
> parentTaxon
= null;
1102 if (parentNode
!= null) {
1103 parentTaxon
= parentNode
.getTaxon();
1107 invokeParentTaxonFkAndTreeIndex(state
.getDbId(parentTaxon
), currentTaxonFk
, treeIndex
);
1113 * Inserts values into the Taxon database table.
1114 * @param taxonName The {@link TaxonNameBase TaxonName}.
1115 * @param state The {@link PesiExportState PesiExportState}.
1116 * @param stmt The prepared statement.
1117 * @return Whether save was successful or not.
1119 protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk
, Integer currentTaxonFk
, StringBuffer treeIndex
) {
1121 if (parentTaxonFk
!= null) {
1122 parentTaxonFk_TreeIndex_KingdomFkStmt
.setInt(1, parentTaxonFk
);
1124 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(1, null);
1127 if (treeIndex
!= null) {
1128 parentTaxonFk_TreeIndex_KingdomFkStmt
.setString(2, treeIndex
.toString());
1130 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(2, null);
1133 if (currentTaxonFk
!= null) {
1134 parentTaxonFk_TreeIndex_KingdomFkStmt
.setInt(3, currentTaxonFk
);
1136 parentTaxonFk_TreeIndex_KingdomFkStmt
.setObject(3, null);
1139 parentTaxonFk_TreeIndex_KingdomFkStmt
.executeUpdate();
1141 } catch (SQLException e
) {
1142 logger
.error("ParentTaxonFk (" + parentTaxonFk
==null?
"-":parentTaxonFk
+ ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk
== null?
"-" :currentTaxonFk
) + ": " + e
.getMessage());
1143 e
.printStackTrace();
1149 * Inserts Rank data and KingdomFk into the Taxon database table.
1150 * @param taxonName The {@link TaxonNameBase TaxonName}.
1151 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1152 * @param taxonFk The TaxonFk to store the values for.
1153 * @param kindomFk The KingdomFk.
1154 * @return Whether save was successful or not.
1156 private boolean invokeRankDataAndKingdomFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
, Integer taxonFk
, Integer kingdomFk
) {
1158 Integer rankFk
= getRankFk(taxonName
, nomenclaturalCode
);
1159 if (rankFk
!= null) {
1160 rankUpdateStmt
.setInt(1, rankFk
);
1162 rankUpdateStmt
.setObject(1, null);
1165 String rankCache
= getRankCache(taxonName
, nomenclaturalCode
);
1166 if (rankCache
!= null) {
1167 rankUpdateStmt
.setString(2, rankCache
);
1169 rankUpdateStmt
.setObject(2, null);
1172 if (kingdomFk
!= null) {
1173 rankUpdateStmt
.setInt(3, kingdomFk
);
1175 rankUpdateStmt
.setObject(3, null);
1178 if (taxonFk
!= null) {
1179 rankUpdateStmt
.setInt(4, taxonFk
);
1181 rankUpdateStmt
.setObject(4, null);
1184 rankUpdateStmt
.executeUpdate();
1186 } catch (SQLException e
) {
1187 logger
.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e
.getMessage());
1188 e
.printStackTrace();
1194 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1195 * @param taxonName The {@link TaxonNameBase TaxonName}.
1196 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1197 * @param taxonFk The TaxonFk to store the values for.
1198 * @param typeNameFk The TypeNameFk.
1199 * @param kindomFk The KingdomFk.
1200 * @param expertFk The ExpertFk.
1201 * @param speciesExpertFk The SpeciesExpertFk.
1202 * @return Whether save was successful or not.
1204 private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
,
1205 Integer taxonFk
, Integer typeNameFk
, Integer kingdomFkk
) {
1208 Integer rankFk
= getRankFk(taxonName
, nomenclaturalCode
);
1209 if (rankFk
!= null) {
1210 rankTypeExpertsUpdateStmt
.setInt(index
++, rankFk
);
1212 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1215 String rankCache
= getRankCache(taxonName
, nomenclaturalCode
);
1216 if (rankCache
!= null) {
1217 rankTypeExpertsUpdateStmt
.setString(index
++, rankCache
);
1219 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1222 if (typeNameFk
!= null) {
1223 rankTypeExpertsUpdateStmt
.setInt(index
++, typeNameFk
);
1225 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1228 if (kingdomFk
!= null) {
1229 rankTypeExpertsUpdateStmt
.setInt(index
++, kingdomFk
);
1231 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1234 // if (expertFk != null) {
1235 // rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1237 // rankTypeExpertsUpdateStmt.setObject(5, null);
1240 // //TODO handle experts GUIDS
1241 // if (speciesExpertFk != null) {
1242 // rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1244 // rankTypeExpertsUpdateStmt.setObject(6, null);
1247 if (taxonFk
!= null) {
1248 rankTypeExpertsUpdateStmt
.setInt(index
++, taxonFk
);
1250 rankTypeExpertsUpdateStmt
.setObject(index
++, null);
1253 rankTypeExpertsUpdateStmt
.executeUpdate();
1255 } catch (SQLException e
) {
1256 logger
.error("Data could not be inserted into database: " + e
.getMessage());
1257 e
.printStackTrace();
1259 } catch (Exception e
) {
1260 logger
.error("Some exception occurred: " + e
.getMessage());
1261 e
.printStackTrace();
1267 * Deletes all entries of database tables related to <code>Taxon</code>.
1268 * @param state The {@link PesiExportState PesiExportState}.
1269 * @return Whether the delete operation was successful or not.
1271 protected boolean doDelete(PesiExportState state
) {
1272 PesiExportConfigurator pesiConfig
= (PesiExportConfigurator
) state
.getConfig();
1275 Source destination
= pesiConfig
.getDestination();
1278 sql
= "DELETE FROM " + dbTableName
;
1279 destination
.setQuery(sql
);
1280 destination
.update(sql
);
1285 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1288 protected boolean isIgnore(PesiExportState state
) {
1289 return ! state
.getConfig().isDoTaxa();
1294 * Creates the kingdom fk.
1298 @SuppressWarnings("unused") //used by mapper
1299 private static Integer
getKingdomFk(TaxonNameBase taxonName
){
1300 return PesiTransformer
.nomenClaturalCode2Kingdom(taxonName
.getNomenclaturalCode());
1304 * Creates the parent fk.
1308 @SuppressWarnings("unused") //used by mapper
1309 private static Integer
getParentTaxonFk(TaxonBase
<?
> taxonBase
, PesiExportState state
){
1310 if (taxonBase
.isInstanceOf(Taxon
.class)){
1311 Taxon taxon
= CdmBase
.deproxy(taxonBase
, Taxon
.class);
1312 if (! isMisappliedName(taxon
)){
1313 Set
<TaxonNode
> nodes
= taxon
.getTaxonNodes();
1314 if (nodes
.size() == 0){
1315 if (taxon
.getName().getRank().isLower(Rank
.KINGDOM())){
1316 logger
.warn("Accepted taxon has no parent. " + taxon
.getTitleCache() + ", " + taxon
.getUuid());
1318 }else if (nodes
.size() > 1){
1319 logger
.warn("Taxon has more than 1 node attached. This is not supported by PESI export." + taxon
.getTitleCache() + ", " + taxon
.getUuid());
1321 Taxon parent
=nodes
.iterator().next().getParent().getTaxon();
1322 return state
.getDbId(parent
);
1330 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1331 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1335 @SuppressWarnings("unused") //used by mapper
1336 private static Integer
getRankFk(TaxonNameBase
<?
,?
> taxonName
) {
1337 return getRankFk(taxonName
, taxonName
.getNomenclaturalCode());
1342 * Returns the <code>RankFk</code> attribute.
1343 * @param taxonName The {@link TaxonNameBase TaxonName}.
1344 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1345 * @return The <code>RankFk</code> attribute.
1348 private static Integer
getRankFk(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
) {
1349 Integer result
= null;
1351 if (nomenclaturalCode
!= null) {
1352 if (taxonName
!= null) {
1353 if (taxonName
.getRank() == null) {
1354 logger
.warn("Rank is null: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1356 result
= PesiTransformer
.rank2RankId(taxonName
.getRank(), PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
));
1358 if (result
== null) {
1359 logger
.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
) + " and TaxonName " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1363 } catch (Exception e
) {
1364 e
.printStackTrace();
1370 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1371 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1375 @SuppressWarnings("unused") //used by mapper
1376 private static String
getRankCache(TaxonNameBase
<?
,?
> taxonName
) {
1377 return getRankCache(taxonName
, taxonName
.getNomenclaturalCode());
1382 * Returns the <code>RankCache</code> attribute.
1383 * @param taxonName The {@link TaxonNameBase TaxonName}.
1384 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1385 * @return The <code>RankCache</code> attribute.
1388 private static String
getRankCache(TaxonNameBase
<?
,?
> taxonName
, NomenclaturalCode nomenclaturalCode
) {
1389 String result
= null;
1391 if (nomenclaturalCode
!= null) {
1392 result
= PesiTransformer
.rank2RankCache(taxonName
.getRank(), PesiTransformer
.nomenClaturalCode2Kingdom(nomenclaturalCode
));
1394 } catch (Exception e
) {
1395 e
.printStackTrace();
1402 * Returns the <code>DisplayName</code> attribute.
1403 * @param taxon The {@link TaxonBase Taxon}.
1404 * @return The <code>DisplayName</code> attribute.
1407 @SuppressWarnings("unused") //used by Mapper
1408 private static String
getDisplayName(TaxonBase
<?
> taxon
) {
1409 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1410 String result
= getDisplayName(taxonName
);
1411 if (isMisappliedName(taxon
)){
1412 result
= result
+ " " + getAuthorString(taxon
);
1418 * Returns the <code>AuthorString</code> attribute.
1419 * @param taxonName The {@link TaxonNameBase TaxonName}.
1420 * @return The <code>AuthorString</code> attribute.
1423 @SuppressWarnings("unused")
1424 protected static String
getAuthorString(TaxonBase
<?
> taxon
) {
1426 String result
= null;
1427 boolean isNonViralName
= false;
1428 String authorshipCache
= null;
1429 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1430 if (taxonName
!= null && taxonName
.isInstanceOf(NonViralName
.class)){
1431 authorshipCache
= CdmBase
.deproxy(taxonName
, NonViralName
.class).getAuthorshipCache();
1432 isNonViralName
= true;
1434 result
= authorshipCache
;
1436 // For a misapplied names there are special rules
1437 if (isMisappliedName(taxon
)){
1438 if (taxon
.getSec() != null){
1439 String secTitle
= taxon
.getSec().getTitleCache();
1440 if (! secTitle
.startsWith("auct")){
1441 secTitle
= "sensu " + secTitle
;
1442 }else if (secTitle
.equals("auct")){ //may be removed once the title cache is generated correctly for references with title auct. #
1446 }else if (StringUtils
.isBlank(authorshipCache
)) {
1447 // Set authorshipCache to "auct."
1448 result
= PesiTransformer
.AUCT_STRING
;
1450 result
= PesiTransformer
.AUCT_STRING
;
1451 // result = authorshipCache;
1455 if (taxonName
== null){
1456 logger
.warn("TaxonName does not exist for taxon: " + taxon
.getUuid() + " (" + taxon
.getTitleCache() + ")");
1457 }else if (! isNonViralName
){
1458 logger
.warn("TaxonName is not of instance NonViralName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1461 if (StringUtils
.isBlank(result
)) {
1466 } catch (Exception e
) {
1467 e
.printStackTrace();
1475 * Returns the <code>DisplayName</code> attribute.
1476 * @param taxonName The {@link TaxonNameBase TaxonName}.
1477 * @return The <code>DisplayName</code> attribute.
1480 @SuppressWarnings("unused") //used by Mapper
1481 private static String
getDisplayName(TaxonNameBase
<?
,?
> taxonName
) {
1483 if (taxonName
== null) {
1486 INonViralNameCacheStrategy
<NonViralName
<?
>> cacheStrategy
= getCacheStrategy(taxonName
);
1487 HTMLTagRules tagRules
= new HTMLTagRules().
1488 addRule(TagEnum
.name
, "i").
1489 addRule(TagEnum
.nomStatus
, "@status@");
1491 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1492 String result
= cacheStrategy
.getFullTitleCache(nvn
, tagRules
);
1493 cacheStrategy
= null;
1495 return result
.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");
1501 * Returns the <code>WebShowName</code> attribute for a taxon.
1502 * @param taxonName The {@link TaxonNameBase TaxonName}.
1503 * @return The <code>WebShowName</code> attribute.
1506 @SuppressWarnings("unused")
1507 private static String
getWebShowName(TaxonBase
<?
> taxon
) {
1508 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
1509 String result
= getWebShowName(taxonName
);
1510 if (isMisappliedName(taxon
)){
1511 result
= result
+ " " + getAuthorString(taxon
);
1517 * Returns the <code>WebShowName</code> attribute.
1518 * @param taxonName The {@link TaxonNameBase TaxonName}.
1519 * @return The <code>WebShowName</code> attribute.
1522 private static String
getWebShowName(TaxonNameBase
<?
,?
> taxonName
) {
1524 if (taxonName
== null) {
1527 INonViralNameCacheStrategy cacheStrategy
= getCacheStrategy(taxonName
);
1529 HTMLTagRules tagRules
= new HTMLTagRules().addRule(TagEnum
.name
, "i");
1530 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1531 String result
= cacheStrategy
.getTitleCache(nvn
, tagRules
);
1532 cacheStrategy
= null;
1540 * Returns the <code>WebSearchName</code> attribute.
1541 * @param taxonName The {@link NonViralName NonViralName}.
1542 * @return The <code>WebSearchName</code> attribute.
1545 @SuppressWarnings("unused")
1546 private static String
getWebSearchName(TaxonNameBase taxonName
) {
1548 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1549 NonViralNameDefaultCacheStrategy strategy
= getCacheStrategy(nvn
);
1550 String result
= strategy
.getNameCache(nvn
);
1558 * Returns the <code>FullName</code> attribute.
1559 * @param taxonName The {@link NonViralName NonViralName}.
1560 * @return The <code>FullName</code> attribute.
1563 @SuppressWarnings("unused")
1564 private static String
getFullName(TaxonNameBase taxonName
) {
1566 NonViralName
<?
> nvn
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1567 String result
= getCacheStrategy(nvn
).getTitleCache(nvn
);
1568 Iterator
<TaxonBase
> taxa
= taxonName
.getTaxa().iterator();
1569 if (taxonName
.getTaxa().size() >0){
1570 if (taxonName
.getTaxa().size() == 1){
1571 TaxonBase taxon
= taxa
.next();
1572 if (isMisappliedName(taxon
)){
1573 result
= result
+ " " + getAuthorString(taxon
);
1584 * Returns the <code>FullName</code> attribute.
1585 * @param taxon The {@link TaxonBase taxon}.
1586 * @return The <code>FullName</code> attribute.
1589 /*@SuppressWarnings("unused")
1590 private static String getFullName(TaxonBase taxon) {
1592 TaxonNameBase name = taxon.getName();
1593 String result = getFullName(name);
1594 if (isMisappliedName(taxon)){
1595 result = result + " " + getAuthorString(taxon);
1603 * Returns the nomenclatural reference which is the reference
1604 * including the detail (microreference).
1605 * @param taxonName The {@link TaxonNameBase TaxonName}.
1606 * @return The <code>AuthorString</code> attribute.
1609 @SuppressWarnings("unused")
1610 private static String
getNomRefString(TaxonNameBase
<?
,?
> taxonName
) {
1611 INomenclaturalReference ref
= taxonName
.getNomenclaturalReference();
1612 return ref
== null ?
null : ref
.getNomenclaturalCitation(taxonName
.getNomenclaturalMicroReference());
1623 * Returns the <code>NameStatusFk</code> attribute.
1624 * @param taxonName The {@link TaxonNameBase TaxonName}.
1625 * @return The <code>NameStatusFk</code> attribute.
1628 @SuppressWarnings("unused")
1629 private static Integer
getNameStatusFk(TaxonNameBase
<?
,?
> taxonName
) {
1630 Integer result
= null;
1632 NomenclaturalStatus state
= getNameStatus(taxonName
);
1633 if (state
!= null) {
1634 result
= PesiTransformer
.nomStatus2nomStatusFk(state
.getType());
1640 * Returns the <code>NameStatusCache</code> attribute.
1641 * @param taxonName The {@link TaxonNameBase TaxonName}.
1642 * @return The <code>NameStatusCache</code> attribute.
1643 * @throws UndefinedTransformerMethodException
1646 @SuppressWarnings("unused")
1647 private static String
getNameStatusCache(TaxonNameBase taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1648 String result
= null;
1649 NomenclaturalStatus status
= getNameStatus(taxonName
);
1650 if (status
!= null) {
1651 result
= state
.getTransformer().getCacheByNomStatus(status
.getType());
1657 private static NomenclaturalStatus
getNameStatus(TaxonNameBase
<?
,?
> taxonName
) {
1660 if (taxonName
!= null && (taxonName
.isInstanceOf(NonViralName
.class))) {
1661 NonViralName
<?
> nonViralName
= CdmBase
.deproxy(taxonName
, NonViralName
.class);
1662 Set
<NomenclaturalStatus
> states
= nonViralName
.getStatus();
1663 if (states
.size() == 1) {
1664 NomenclaturalStatus status
= states
.iterator().next();
1666 } else if (states
.size() > 1) {
1667 logger
.error("This TaxonName has more than one Nomenclatural Status: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1671 } catch (Exception e
) {
1672 e
.printStackTrace();
1677 * Returns the <code>TaxonStatusFk</code> attribute.
1678 * @param taxonName The {@link TaxonNameBase TaxonName}.
1679 * @param state The {@link PesiExportState PesiExportState}.
1680 * @return The <code>TaxonStatusFk</code> attribute.
1683 @SuppressWarnings("unused")
1684 private static Integer
getTaxonStatusFk(TaxonBase
<?
> taxon
, PesiExportState state
) {
1685 Integer result
= null;
1688 if (isMisappliedName(taxon
)) {
1689 Synonym synonym
= Synonym
.NewInstance(null, null);
1691 // This works as long as only the instance is important to differentiate between TaxonStatus.
1692 result
= PesiTransformer
.taxonBase2statusFk(synonym
); // Auct References are treated as Synonyms in Datawarehouse now.
1694 result
= PesiTransformer
.taxonBase2statusFk(taxon
);
1697 } catch (Exception e
) {
1698 e
.printStackTrace();
1704 * Returns the <code>TaxonStatusCache</code> attribute.
1705 * @param taxonName The {@link TaxonNameBase TaxonName}.
1706 * @param state The {@link PesiExportState PesiExportState}.
1707 * @return The <code>TaxonStatusCache</code> attribute.
1710 @SuppressWarnings("unused")
1711 private static String
getTaxonStatusCache(TaxonBase
<?
> taxon
, PesiExportState state
) {
1712 String result
= null;
1715 if (isMisappliedName(taxon
)) {
1716 Synonym synonym
= Synonym
.NewInstance(null, null);
1718 // This works as long as only the instance is important to differentiate between TaxonStatus.
1719 result
= PesiTransformer
.taxonBase2statusCache(synonym
); // Auct References are treated as Synonyms in Datawarehouse now.
1721 result
= PesiTransformer
.taxonBase2statusCache(taxon
);
1724 } catch (Exception e
) {
1725 e
.printStackTrace();
1731 * Returns the <code>TypeNameFk</code> attribute.
1732 * @param taxonName The {@link TaxonNameBase TaxonName}.
1733 * @param state The {@link PesiExportState PesiExportState}.
1734 * @return The <code>TypeNameFk</code> attribute.
1737 private static Integer
getTypeNameFk(TaxonNameBase
<?
,?
> taxonNameBase
, PesiExportState state
) {
1738 Integer result
= null;
1739 if (taxonNameBase
!= null) {
1740 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonNameBase
.getNameTypeDesignations();
1741 if (nameTypeDesignations
.size() == 1) {
1742 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1743 if (nameTypeDesignation
!= null) {
1744 TaxonNameBase
<?
,?
> typeName
= nameTypeDesignation
.getTypeName();
1745 if (typeName
!= null) {
1746 result
= state
.getDbId(typeName
);
1749 } else if (nameTypeDesignations
.size() > 1) {
1750 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonNameBase
.getUuid() + " (" + taxonNameBase
.getTitleCache() + ")");
1757 * Returns the <code>TypeFullnameCache</code> attribute.
1758 * @param taxonName The {@link TaxonNameBase TaxonName}.
1759 * @return The <code>TypeFullnameCache</code> attribute.
1762 @SuppressWarnings("unused")
1763 private static String
getTypeFullnameCache(TaxonNameBase
<?
,?
> taxonName
) {
1764 String result
= null;
1767 if (taxonName
!= null) {
1768 Set
<NameTypeDesignation
> nameTypeDesignations
= taxonName
.getNameTypeDesignations();
1769 if (nameTypeDesignations
.size() == 1) {
1770 NameTypeDesignation nameTypeDesignation
= nameTypeDesignations
.iterator().next();
1771 if (nameTypeDesignation
!= null) {
1772 TaxonNameBase
<?
,?
> typeName
= nameTypeDesignation
.getTypeName();
1773 if (typeName
!= null) {
1774 result
= typeName
.getTitleCache();
1777 } else if (nameTypeDesignations
.size() > 1) {
1778 logger
.warn("This TaxonName has " + nameTypeDesignations
.size() + " NameTypeDesignations: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1782 } catch (Exception e
) {
1783 e
.printStackTrace();
1790 * Returns the <code>QualityStatusFk</code> attribute.
1791 * @param taxonName The {@link TaxonNameBase TaxonName}.
1792 * @return The <code>QualityStatusFk</code> attribute.
1795 private static Integer
getQualityStatusFk(TaxonNameBase taxonName
) {
1796 BitSet sources
= getSources(taxonName
);
1797 return PesiTransformer
.getQualityStatusKeyBySource(sources
, taxonName
);
1802 * Returns the <code>QualityStatusCache</code> attribute.
1803 * @param taxonName The {@link TaxonNameBase TaxonName}.
1804 * @return The <code>QualityStatusCache</code> attribute.
1805 * @throws UndefinedTransformerMethodException
1808 @SuppressWarnings("unused")
1809 private static String
getQualityStatusCache(TaxonNameBase taxonName
, PesiExportState state
) throws UndefinedTransformerMethodException
{
1810 return state
.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName
));
1815 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1816 * @param taxonName The {@link TaxonNameBase TaxonName}.
1817 * @return The <code>TypeDesignationStatusFk</code> attribute.
1820 @SuppressWarnings("unused")
1821 private static Integer
getTypeDesignationStatusFk(TaxonNameBase
<?
,?
> taxonName
) {
1822 Integer result
= null;
1825 if (taxonName
!= null) {
1826 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1827 if (typeDesignations
.size() == 1) {
1828 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1829 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1830 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus
);
1831 } else if (typeDesignations
.size() > 1) {
1832 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1836 } catch (Exception e
) {
1837 e
.printStackTrace();
1843 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1844 * @param taxonName The {@link TaxonNameBase TaxonName}.
1845 * @return The <code>TypeDesignationStatusCache</code> attribute.
1848 @SuppressWarnings("unused")
1849 private static String
getTypeDesignationStatusCache(TaxonNameBase
<?
,?
> taxonName
) {
1850 String result
= null;
1853 if (taxonName
!= null) {
1854 Set
<NameTypeDesignation
> typeDesignations
= taxonName
.getNameTypeDesignations();
1855 if (typeDesignations
.size() == 1) {
1856 Object obj
= typeDesignations
.iterator().next().getTypeStatus();
1857 NameTypeDesignationStatus designationStatus
= CdmBase
.deproxy(obj
, NameTypeDesignationStatus
.class);
1858 result
= PesiTransformer
.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus
);
1859 } else if (typeDesignations
.size() > 1) {
1860 logger
.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
1864 } catch (Exception e
) {
1865 e
.printStackTrace();
1871 * Returns the <code>FossilStatusFk</code> attribute.
1872 * @param taxonName The {@link TaxonNameBase TaxonName}.
1873 * @return The <code>FossilStatusFk</code> attribute.
1876 @SuppressWarnings("unused")
1877 private static Integer
getFossilStatusFk(IdentifiableEntity
<?
> identEntity
, PesiExportState state
) {
1878 Integer result
= null;
1880 Set
<String
> fossilStatuus
= identEntity
.getExtensions(ErmsTransformer
.uuidFossilStatus
);
1881 if (fossilStatuus
.size() == 0){
1883 }else if (fossilStatuus
.size() > 1){
1884 logger
.warn("More than 1 fossil status given for " + identEntity
.getTitleCache() + " " + identEntity
.getUuid());
1886 String fossilStatus
= fossilStatuus
.iterator().next();
1888 int statusFk
= state
.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus
);
1893 * Returns the <code>FossilStatusCache</code> attribute.
1894 * @param taxonName The {@link TaxonNameBase TaxonName}.
1895 * @return The <code>FossilStatusCache</code> attribute.
1898 @SuppressWarnings("unused")
1899 private static String
getFossilStatusCache(IdentifiableEntity
<?
> identEntity
, PesiExportState state
) {
1900 String result
= null;
1901 Set
<String
> fossilStatuus
= identEntity
.getExtensions(ErmsTransformer
.uuidFossilStatus
);
1902 if (fossilStatuus
.size() == 0){
1905 for (String strFossilStatus
: fossilStatuus
){
1906 result
= CdmUtils
.concat(";", result
, strFossilStatus
);
1912 * Returns the <code>IdInSource</code> attribute.
1913 * @param taxonName The {@link TaxonNameBase TaxonName}.
1914 * @return The <code>IdInSource</code> attribute.
1917 @SuppressWarnings("unused")
1918 private static String
getIdInSource(IdentifiableEntity taxonName
) {
1919 String result
= null;
1922 Set
<IdentifiableSource
> sources
= getPesiSources(taxonName
);
1923 if (sources
.size() > 1){
1924 logger
.warn("There is > 1 Pesi source. This is not yet handled.");
1926 if (sources
.size() == 0){
1927 logger
.warn("There is no Pesi source!" +taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
1929 for (IdentifiableSource source
: sources
) {
1930 Reference
<?
> ref
= source
.getCitation();
1931 UUID refUuid
= ref
.getUuid();
1932 String idInSource
= source
.getIdInSource();
1933 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
1934 result
= idInSource
!= null ?
("NameId: " + source
.getIdInSource()) : null;
1935 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
1936 result
= idInSource
!= null ?
("TAX_ID: " + source
.getIdInSource()) : null;
1937 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
1938 result
= idInSource
!= null ?
("tu_id: " + source
.getIdInSource()) : null;
1939 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){ //Index Fungorum
1940 result
= idInSource
!= null ?
("if_id: " + source
.getIdInSource()) : null;
1942 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");};
1945 String sourceIdNameSpace
= source
.getIdNamespace();
1946 if (sourceIdNameSpace
!= null) {
1947 if (sourceIdNameSpace
.equals(PesiTransformer
.STR_NAMESPACE_NOMINAL_TAXON
)) {
1948 result
= idInSource
!= null ?
("Nominal Taxon from TAX_ID: " + source
.getIdInSource()):null;
1949 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_EPITHET_NAMESPACE
)) {
1950 result
= idInSource
!= null ?
("Inferred epithet from TAX_ID: " + source
.getIdInSource()) : null;
1951 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.INFERRED_GENUS_NAMESPACE
)) {
1952 result
= idInSource
!= null ?
("Inferred genus from TAX_ID: " + source
.getIdInSource()):null;
1953 } else if (sourceIdNameSpace
.equals(TaxonServiceImpl
.POTENTIAL_COMBINATION_NAMESPACE
)) {
1954 result
= idInSource
!= null ?
("Potential combination from TAX_ID: " + source
.getIdInSource()):null;
1957 if (result
== null) {
1958 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +", sourceIdNameSpace: " + source
.getIdNamespace()+")");
1961 } catch (Exception e
) {
1962 e
.printStackTrace();
1963 logger
.error("An error occurs while creating idInSource..." + taxonName
.getUuid() + " (" + taxonName
.getTitleCache()+ e
.getMessage());
1966 if (result
== null) {
1967 logger
.warn("IdInSource is NULL for this taxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() +")");
1973 * Returns the idInSource for a given TaxonName only.
1974 * @param taxonName The {@link TaxonNameBase TaxonName}.
1975 * @return The idInSource.
1977 private static String
getIdInSourceOnly(IdentifiableEntity identEntity
) {
1978 String result
= null;
1980 // Get the sources first
1981 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
1983 // Determine the idInSource
1984 if (sources
.size() == 1) {
1985 IdentifiableSource source
= sources
.iterator().next();
1986 if (source
!= null) {
1987 result
= source
.getIdInSource();
1989 } else if (sources
.size() > 1) {
1992 for (IdentifiableSource source
: sources
) {
1993 result
+= source
.getIdInSource();
1994 if (count
< sources
.size()) {
2006 * Returns the Sources for a given TaxonName only.
2007 * @param taxonName The {@link TaxonNameBase TaxonName}.
2008 * @return The Sources.
2010 private static Set
<IdentifiableSource
> getPesiSources(IdentifiableEntity identEntity
) {
2011 Set
<IdentifiableSource
> sources
= new java
.util
.HashSet
<IdentifiableSource
>();
2014 if (identEntity
.isInstanceOf(TaxonNameBase
.class)){
2015 // Sources from TaxonName
2016 TaxonNameBase taxonName
= CdmBase
.deproxy(identEntity
, TaxonNameBase
.class);
2017 Set
<IdentifiableSource
> testSources
= identEntity
.getSources();
2018 sources
= filterPesiSources(identEntity
.getSources());
2020 if (sources
.size() == 0 && testSources
.size()>0){
2021 IdentifiableSource source
= testSources
.iterator().next();
2022 logger
.warn("There are sources, but they are no pesi sources!!!" + source
.getIdInSource() + " - " + source
.getIdNamespace() + " - "+source
.getCitation().generateTitle());
2024 if (sources
.size() > 1) {
2025 logger
.warn("This TaxonName has more than one Source: " + identEntity
.getUuid() + " (" + identEntity
.getTitleCache() + ")");
2028 // name has no PESI source, take sources from TaxonBase
2029 if (sources
== null || sources
.isEmpty()) {
2030 Set
<TaxonBase
> taxa
= taxonName
.getTaxonBases();
2031 for (TaxonBase taxonBase
: taxa
){
2032 sources
.addAll(filterPesiSources(taxonBase
.getSources()));
2037 }else if (identEntity
.isInstanceOf(TaxonBase
.class)){
2038 sources
= filterPesiSources(identEntity
.getSources());
2041 /*TODO: deleted only for testing the inferred synonyms
2042 if (sources == null || sources.isEmpty()) {
2043 logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2044 }else if (sources.size() > 1){
2045 logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2051 // return all sources with a PESI reference
2052 private static Set
<IdentifiableSource
> filterPesiSources(Set
<?
extends IdentifiableSource
> sources
) {
2053 Set
<IdentifiableSource
> result
= new HashSet
<IdentifiableSource
>();
2054 for (IdentifiableSource source
: sources
){
2055 Reference ref
= source
.getCitation();
2056 UUID refUuid
= ref
.getUuid();
2057 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
) ||
2058 refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)||
2059 refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)||
2060 refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
) ||
2061 refUuid
.equals(PesiTransformer
.uuidSourceRefAuct
)){
2069 * Returns the <code>GUID</code> attribute.
2070 * @param taxonName The {@link TaxonNameBase TaxonName}.
2071 * @return The <code>GUID</code> attribute.
2074 private static String
getGUID(TaxonBase
<?
> taxon
) {
2075 if (taxon
.getLsid() != null ){
2076 return taxon
.getLsid().getLsid();
2077 }else if (taxon
.hasMarker(PesiTransformer
.uuidMarkerGuidIsMissing
, true)){
2080 return taxon
.getUuid().toString();
2088 * Returns the <code>DerivedFromGuid</code> attribute.
2089 * @param taxonName The {@link TaxonNameBase TaxonName}.
2090 * @return The <code>DerivedFromGuid</code> attribute.
2093 @SuppressWarnings("unused")
2094 private static String
getDerivedFromGuid(TaxonBase
<?
> taxon
) {
2095 String result
= null;
2097 // The same as GUID for now
2098 result
= getGUID(taxon
);
2099 } catch (Exception e
) {
2100 e
.printStackTrace();
2106 * Returns the <code>CacheCitation</code> attribute.
2107 * @param taxonName The {@link TaxonNameBase TaxonName}.
2108 * @return The CacheCitation.
2111 @SuppressWarnings("unused")
2112 private static String
getCacheCitation(TaxonBase taxon
) {
2113 // !!! See also doPhaseUpdates
2115 TaxonNameBase
<?
,?
> taxonName
= taxon
.getName();
2117 //TODO implement anew for taxa
2119 BitSet sources
= getSources(taxonName
);
2120 if (sources
.isEmpty()) {
2121 // logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2122 } else if (sources
.get(PesiTransformer
.SOURCE_ERMS
)) {
2123 // 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...
2124 // So the following code is some kind of harmless assumption.
2125 Set
<Extension
> extensions
= taxonName
.getExtensions();
2126 for (Extension extension
: extensions
) {
2127 if (extension
.getType().equals(cacheCitationExtensionType
)) {
2128 result
= extension
.getValue();
2132 String expertName
= getExpertName(taxon
);
2133 String webShowName
= getWebShowName(taxonName
);
2136 String idInSource
= getIdInSourceOnly(taxonName
);
2138 // build the cacheCitation
2139 if (expertName
!= null) {
2140 result
+= expertName
+ ". ";
2142 if (logger
.isDebugEnabled()){logger
.debug("ExpertName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");}
2144 if (webShowName
!= null) {
2145 result
+= webShowName
+ ". ";
2147 logger
.warn("WebShowName could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
2150 if (getOriginalDB(taxonName
).equals("FaEu")) {
2151 result
+= "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
2152 } else if (getOriginalDB(taxonName
).equals("EM")) {
2153 result
+= "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
2156 if (idInSource
!= null) {
2157 result
+= idInSource
;
2159 logger
.warn("IdInSource could not be determined for this TaxonName: " + taxonName
.getUuid() + " (" + taxonName
.getTitleCache() + ")");
2162 } catch (Exception e
) {
2163 e
.printStackTrace();
2166 if (StringUtils
.isBlank(result
)) {
2174 * Returns the <code>OriginalDB</code> attribute.
2175 * @param taxonName The {@link TaxonNameBase TaxonName}.
2176 * @return The <code>OriginalDB</code> attribute.
2179 private static String
getOriginalDB(IdentifiableEntity identEntity
) {
2180 // Sources from TaxonName
2181 BitSet sources
= getSources(identEntity
);
2182 return PesiTransformer
.getOriginalDbBySources(sources
);
2186 * Returns the <code>LastAction</code> attribute.
2187 * @param taxonName The {@link TaxonNameBase TaxonName}.
2188 * @return The <code>LastAction</code> attribute.
2191 @SuppressWarnings("unused")
2192 private static String
getLastAction(IdentifiableEntity
<?
> identEntity
) {
2193 String result
= null;
2195 Set
<Extension
> extensions
= identEntity
.getExtensions();
2196 for (Extension extension
: extensions
) {
2197 if (extension
.getType().equals(lastActionExtensionType
)) {
2198 result
= extension
.getValue();
2201 } catch (Exception e
) {
2202 e
.printStackTrace();
2208 * Returns the <code>LastActionDate</code> attribute.
2209 * @param taxonName The {@link TaxonNameBase TaxonName}.
2210 * @return The <code>LastActionDate</code> attribute.
2213 @SuppressWarnings({ "unused" })
2214 private static DateTime
getLastActionDate(IdentifiableEntity identEntity
) {
2215 DateTime result
= null;
2217 Set
<Extension
> extensions
= identEntity
.getExtensions();
2218 for (Extension extension
: extensions
) {
2219 if (extension
.getType().equals(lastActionDateExtensionType
)) {
2220 String dateTime
= extension
.getValue();
2221 if (dateTime
!= null) {
2222 DateTimeFormatter formatter
= DateTimeFormat
.forPattern("yyyy-MM-dd HH:mm:ss.S");
2223 result
= formatter
.parseDateTime(dateTime
);
2227 } catch (Exception e
) {
2228 e
.printStackTrace();
2234 * Returns the <code>ExpertName</code> attribute.
2235 * @param taxonName The {@link TaxonNameBase TaxonName}.
2236 * @return The <code>ExpertName</code> attribute.
2239 @SuppressWarnings("unused")
2240 private static String
getExpertName(TaxonBase
<?
> taxonName
) {
2241 String result
= null;
2243 Set
<Extension
> extensions
= taxonName
.getExtensions();
2244 for (Extension extension
: extensions
) {
2245 if (extension
.getType().equals(expertNameExtensionType
)) {
2246 result
= extension
.getValue();
2249 } catch (Exception e
) {
2250 e
.printStackTrace();
2256 * Returns the <code>ExpertFk</code> attribute.
2257 * @param taxonName The {@link TaxonNameBase TaxonName}.
2258 * @param state The {@link PesiExportState PesiExportState}.
2259 * @return The <code>ExpertFk</code> attribute.
2262 private static Integer
getExpertFk(Reference
<?
> reference
, PesiExportState state
) {
2263 Integer result
= state
.getDbId(reference
);
2268 * Returns the <code>SpeciesExpertName</code> attribute.
2269 * @param taxonName The {@link TaxonNameBase TaxonName}.
2270 * @return The <code>SpeciesExpertName</code> attribute.
2273 @SuppressWarnings("unused")
2274 private static String
getSpeciesExpertName(TaxonBase
<?
> taxonName
) {
2275 String result
= null;
2277 Set
<Extension
> extensions
= taxonName
.getExtensions();
2278 for (Extension extension
: extensions
) {
2279 if (extension
.getType().equals(speciesExpertNameExtensionType
)) {
2280 result
= extension
.getValue();
2283 } catch (Exception e
) {
2284 e
.printStackTrace();
2290 * Returns the <code>SpeciesExpertFk</code> attribute.
2291 * @param reference The {@link Reference Reference}.
2292 * @param state The {@link PesiExportState PesiExportState}.
2293 * @return The <code>SpeciesExpertFk</code> attribute.
2296 private static Integer
getSpeciesExpertFk(Reference
<?
> reference
, PesiExportState state
) {
2297 Integer result
= state
.getDbId(reference
);
2303 * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
2304 * Identifiable Entity as a BitSet
2305 * @param identEntity
2308 private static BitSet
getSources(IdentifiableEntity
<?
> identEntity
){
2309 BitSet bitSet
= new BitSet();
2310 Set
<IdentifiableSource
> sources
= getPesiSources(identEntity
);
2311 for (IdentifiableSource source
: sources
) {
2312 Reference
<?
> ref
= source
.getCitation();
2313 UUID refUuid
= ref
.getUuid();
2314 if (refUuid
.equals(PesiTransformer
.uuidSourceRefEuroMed
)){
2315 bitSet
.set(PesiTransformer
.SOURCE_EM
);
2316 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefFaunaEuropaea
)){
2317 bitSet
.set(PesiTransformer
.SOURCE_FE
);
2318 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefErms
)){
2319 bitSet
.set(PesiTransformer
.SOURCE_ERMS
);
2320 }else if (refUuid
.equals(PesiTransformer
.uuidSourceRefIndexFungorum
)){
2321 bitSet
.set(PesiTransformer
.SOURCE_IF
);
2323 if (logger
.isDebugEnabled()){logger
.debug("Not a PESI source");};
2330 protected static NonViralNameDefaultCacheStrategy
getCacheStrategy(TaxonNameBase
<?
, ?
> taxonName
) {
2331 taxonName
= CdmBase
.deproxy(taxonName
, TaxonNameBase
.class);
2332 NonViralNameDefaultCacheStrategy
<?
> cacheStrategy
;
2333 if (taxonName
.isInstanceOf(ZoologicalName
.class)){
2334 cacheStrategy
= zooNameStrategy
;
2335 }else if (taxonName
.isInstanceOf(BotanicalName
.class)) {
2336 cacheStrategy
= botanicalNameStrategy
;
2337 }else if (taxonName
.getClass().equals(NonViralName
.class)) {
2338 cacheStrategy
= nonViralNameStrategy
;
2339 }else if (taxonName
.getClass().equals(BacterialName
.class)) {
2340 cacheStrategy
= bacterialNameStrategy
;
2342 logger
.error("Unhandled taxon name type. Can't define strategy class");
2343 cacheStrategy
= botanicalNameStrategy
;
2345 return cacheStrategy
;
2349 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
2350 * @param relationship The {@link RelationshipBase Relationship}.
2351 * @param state The {@link PesiExportState PesiExportState}.
2352 * @return The <code>TaxonFk1</code> attribute.
2355 private static Integer
getTaxonFk1(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
) {
2357 return getObjectFk(relationship
, state
, true);
2361 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
2362 * @param relationship The {@link RelationshipBase Relationship}.
2363 * @param state The {@link PesiExportState PesiExportState}.
2364 * @return The <code>TaxonFk2</code> attribute.
2367 private static Integer
getTaxonFk2(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
) {
2368 return getObjectFk(relationship
, state
, false);
2372 * Returns the database key of an object in the given relationship.
2373 * @param relationship {@link RelationshipBase RelationshipBase}.
2374 * @param state {@link PesiExportState PesiExportState}.
2375 * @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.
2376 * @return The database key of an object in the given relationship.
2378 private static Integer
getObjectFk(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
, boolean isFrom
) {
2379 TaxonBase
<?
> taxonBase
= null;
2380 if (relationship
.isInstanceOf(TaxonRelationship
.class)) {
2381 TaxonRelationship tr
= (TaxonRelationship
)relationship
;
2382 taxonBase
= (isFrom
) ? tr
.getFromTaxon(): tr
.getToTaxon();
2383 } else if (relationship
.isInstanceOf(SynonymRelationship
.class)) {
2384 SynonymRelationship sr
= (SynonymRelationship
)relationship
;
2385 taxonBase
= (isFrom
) ? sr
.getSynonym() : sr
.getAcceptedTaxon();
2386 } else if (relationship
.isInstanceOf(NameRelationship
.class) || relationship
.isInstanceOf(HybridRelationship
.class)) {
2388 return state
.getDbId(state
.getCurrentFromObject());
2390 return state
.getDbId(state
.getCurrentToObject());
2393 if (taxonBase
!= null) {
2394 if (! isPesiTaxon(taxonBase
)){
2395 logger
.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase
.getId() + "/" + taxonBase
.getUuid() + "; TaxonRel: " + relationship
.getId() + "(" + relationship
.getType().getTitleCache() + ")");
2398 return state
.getDbId(taxonBase
);
2402 logger
.warn("No taxon found in state for relationship: " + relationship
.toString());
2407 * Returns the <code>RelQualifierCache</code> attribute.
2408 * @param relationship The {@link RelationshipBase Relationship}.
2409 * @return The <code>RelQualifierCache</code> attribute.
2412 @SuppressWarnings("unused")
2413 private static String
getRelQualifierCache(RelationshipBase
<?
, ?
, ?
> relationship
, PesiExportState state
) {
2414 String result
= null;
2415 NomenclaturalCode code
= null;
2416 if (relationship
.isInstanceOf(TaxonRelationship
.class)){
2417 code
= CdmBase
.deproxy(relationship
, TaxonRelationship
.class).getToTaxon().getName().getNomenclaturalCode();
2418 }else if (relationship
.isInstanceOf(SynonymRelationship
.class)){
2419 code
= CdmBase
.deproxy(relationship
, SynonymRelationship
.class).getAcceptedTaxon().getName().getNomenclaturalCode();
2420 }else if (relationship
.isInstanceOf(NameRelationship
.class)){
2421 code
= CdmBase
.deproxy(relationship
, NameRelationship
.class).getFromName().getNomenclaturalCode();
2422 }else if (relationship
.isInstanceOf(HybridRelationship
.class)){
2423 code
= CdmBase
.deproxy(relationship
, HybridRelationship
.class).getParentName().getNomenclaturalCode();
2426 result
= state
.getConfig().getTransformer().getCacheByRelationshipType(relationship
, code
);
2428 logger
.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship
.getUuid());
2434 * Returns the <code>RelTaxonQualifierFk</code> attribute.
2435 * @param relationship The {@link RelationshipBase Relationship}.
2436 * @return The <code>RelTaxonQualifierFk</code> attribute.
2439 @SuppressWarnings("unused")
2440 private static Integer
getRelTaxonQualifierFk(RelationshipBase
<?
, ?
, ?
> relationship
) {
2441 return PesiTransformer
.taxonRelation2RelTaxonQualifierFk(relationship
);
2444 * Returns the <code>Notes</code> attribute.
2445 * @param relationship The {@link RelationshipBase Relationship}.
2446 * @return The <code>Notes</code> attribute.
2449 @SuppressWarnings("unused")
2450 private static String
getNotes(RelationshipBase
<?
, ?
, ?
> relationship
) {
2456 // * Returns the <code>SourceFk</code> attribute.
2457 // * @param taxonName The {@link TaxonNameBase TaxonName}.
2458 // * @param state The {@link PesiExportState PesiExportState}.
2459 // * @return The <code>SourceFk</code> attribute.
2461 // @SuppressWarnings("unused")
2462 // private static Integer getSourceFk(TaxonNameBase<?,?> taxonName, PesiExportState state) {
2463 // Integer result = null;
2466 // TaxonBase<?> taxonBase = getSourceTaxonBase(taxonName);
2468 // if (taxonBase != null) {
2469 // result = state.getDbId(taxonBase.getSec());
2471 // } catch (Exception e) {
2472 // e.printStackTrace();
2479 // * Determines the TaxonBase of a TaxonName.
2480 // * @param taxonName The {@link TaxonNameBase TaxonName}.
2481 // * @return The TaxonBase.
2483 // private static TaxonBase<?> getSourceTaxonBase(TaxonNameBase<?,?> taxonName) {
2484 // TaxonBase<?> taxonBase = null;
2485 // Set<Taxon> taxa = taxonName.getTaxa();
2486 // if (taxa.size() == 1) {
2487 // taxonBase =taxa.iterator().next();
2488 // } else if (taxa.size() > 1) {
2489 // logger.warn("This TaxonName has " + taxa.size() + " Taxa: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2492 // Set<Synonym> synonyms = taxonName.getSynonyms();
2493 // if (synonyms.size() == 1) {
2494 // taxonBase = synonyms.iterator().next();
2495 // } else if (synonyms.size() > 1) {
2496 // logger.warn("This TaxonName has " + synonyms.size() + " Synonyms: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2498 // return taxonBase;
2502 * Returns the CDM to PESI specific export mappings.
2503 * @return The {@link PesiExportMapping PesiExportMapping}.
2505 private PesiExportMapping
getMapping() {
2506 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2508 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2509 mapping
.addMapper(DbObjectMapper
.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2510 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter
, PesiExportState
.class));
2511 mapping
.addMapper(MethodMapper
.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter
, PesiExportState
.class));
2513 mapping
.addMapper(MethodMapper
.NewInstance("GUID", this));
2515 mapping
.addMapper(MethodMapper
.NewInstance("DerivedFromGuid", this));
2516 mapping
.addMapper(MethodMapper
.NewInstance("CacheCitation", this));
2517 mapping
.addMapper(MethodMapper
.NewInstance("AuthorString", this)); //For Taxon because Misallied Names are handled differently
2518 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this));
2521 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this));
2523 // FossilStatus (Fk, Cache)
2524 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusCache", this, IdentifiableEntity
.class, PesiExportState
.class));
2525 mapping
.addMapper(MethodMapper
.NewInstance("FossilStatusFk", this, IdentifiableEntity
.class, PesiExportState
.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2527 //handled by name mapping
2528 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2529 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2532 ExtensionType extensionTypeSpeciesExpertName
= (ExtensionType
)getTermService().find(PesiTransformer
.speciesExpertNameUuid
);
2533 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionTypeSpeciesExpertName
, "SpeciesExpertName"));
2534 ExtensionType extensionTypeExpertName
= (ExtensionType
)getTermService().find(PesiTransformer
.expertNameUuid
);
2535 mapping
.addMapper(DbExtensionMapper
.NewInstance(extensionTypeExpertName
, "ExpertName"));
2537 // mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class)); //by AM, doesn't work, FK exception
2538 mapping
.addMapper(ObjectChangeMapper
.NewInstance(TaxonBase
.class, TaxonNameBase
.class, "Name"));
2540 addNameMappers(mapping
);
2546 * Returns the CDM to PESI specific export mappings.
2547 * @return The {@link PesiExportMapping PesiExportMapping}.
2549 private PesiExportMapping
getPureNameMapping() {
2550 PesiExportMapping mapping
= new PesiExportMapping(dbTableName
);
2552 mapping
.addMapper(IdMapper
.NewInstance("TaxonId"));
2554 // mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2556 mapping
.addMapper(MethodMapper
.NewInstance("KingdomFk", this, TaxonNameBase
.class));
2557 mapping
.addMapper(MethodMapper
.NewInstance("RankFk", this, TaxonNameBase
.class));
2558 mapping
.addMapper(MethodMapper
.NewInstance("RankCache", this, TaxonNameBase
.class));
2559 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusFk", Types
.INTEGER
, PesiTransformer
.T_STATUS_UNACCEPTED
));
2560 mapping
.addMapper(DbConstantMapper
.NewInstance("TaxonStatusCache", Types
.VARCHAR
, PesiTransformer
.T_STATUS_STR_UNACCEPTED
));
2561 mapping
.addMapper(DbStringMapper
.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
2562 mapping
.addMapper(MethodMapper
.NewInstance("WebShowName", this, TaxonNameBase
.class));
2565 mapping
.addMapper(MethodMapper
.NewInstance("DisplayName", this, TaxonNameBase
.class));
2567 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastActionDate", false));
2568 mapping
.addMapper(DbLastActionMapper
.NewInstance("LastAction", true));
2570 addNameMappers(mapping
);
2571 //TODO add author mapper, TypeNameFk
2576 private void addNameMappers(PesiExportMapping mapping
) {
2577 mapping
.addMapper(DbStringMapper
.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2578 mapping
.addMapper(DbStringMapper
.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2579 mapping
.addMapper(DbStringMapper
.NewInstance("SpecificEpithet", "SpecificEpithet"));
2580 mapping
.addMapper(DbStringMapper
.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2582 // mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName")); //does not work as we need other cache strategy
2583 mapping
.addMapper(MethodMapper
.NewInstance("WebSearchName", this, TaxonNameBase
.class));
2585 // mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName")); //does not work as we need other cache strategy
2586 mapping
.addMapper(MethodMapper
.NewInstance("FullName", this, TaxonNameBase
.class));
2589 mapping
.addMapper(MethodMapper
.NewInstance("NomRefString", this, TaxonNameBase
.class));
2591 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusFk", this, TaxonNameBase
.class));
2592 mapping
.addMapper(MethodMapper
.NewInstance("NameStatusCache", this, TaxonNameBase
.class, PesiExportState
.class));
2593 mapping
.addMapper(MethodMapper
.NewInstance("TypeFullnameCache", this, TaxonNameBase
.class));
2597 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusFk", this, TaxonNameBase
.class));
2598 mapping
.addMapper(MethodMapper
.NewInstance("QualityStatusCache", this, TaxonNameBase
.class, PesiExportState
.class));
2600 mapping
.addMapper(MethodMapper
.NewInstance("IdInSource", this, IdentifiableEntity
.class));
2601 mapping
.addMapper(MethodMapper
.NewInstance("OriginalDB", this, IdentifiableEntity
.class) );
2603 //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2607 private PesiExportMapping
getSynRelMapping() {
2608 PesiExportMapping mapping
= new PesiExportMapping(dbTableNameSynRel
);
2610 mapping
.addMapper(MethodMapper
.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase
.class, PesiExportState
.class));
2611 mapping
.addMapper(MethodMapper
.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase
.class, PesiExportState
.class));
2612 mapping
.addMapper(MethodMapper
.NewInstance("RelTaxonQualifierFk", this, RelationshipBase
.class));
2613 mapping
.addMapper(MethodMapper
.NewInstance("RelQualifierCache", this, RelationshipBase
.class, PesiExportState
.class));
2614 mapping
.addMapper(MethodMapper
.NewInstance("Notes", this, RelationshipBase
.class));