move ProfilerController to cdmlib-persistence-test and remove parent pom from PESI
[cdmlib-apps.git] / cdm-pesi / src / main / java / eu / etaxonomy / cdm / io / pesi / out / PesiTaxonExport.java
1 // $Id$
2 /**
3 * Copyright (C) 2009 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
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.
9 */
10 package eu.etaxonomy.cdm.io.pesi.out;
11
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;
23 import java.util.Set;
24 import java.util.UUID;
25
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;
33
34 import eu.etaxonomy.cdm.api.service.TaxonServiceImpl;
35 import eu.etaxonomy.cdm.common.CdmUtils;
36 import eu.etaxonomy.cdm.io.common.Source;
37 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
38 import eu.etaxonomy.cdm.io.common.mapping.out.DbConstantMapper;
39 import eu.etaxonomy.cdm.io.common.mapping.out.DbExtensionMapper;
40 import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;
41 import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
42 import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
43 import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
44 import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
45 import eu.etaxonomy.cdm.io.common.mapping.out.ObjectChangeMapper;
46 import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;
47 import eu.etaxonomy.cdm.model.common.Annotation;
48 import eu.etaxonomy.cdm.model.common.AnnotationType;
49 import eu.etaxonomy.cdm.model.common.CdmBase;
50 import eu.etaxonomy.cdm.model.common.Extension;
51 import eu.etaxonomy.cdm.model.common.ExtensionType;
52 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
53 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
54 import eu.etaxonomy.cdm.model.common.Language;
55 import eu.etaxonomy.cdm.model.common.Marker;
56 import eu.etaxonomy.cdm.model.common.MarkerType;
57 import eu.etaxonomy.cdm.model.common.RelationshipBase;
58 import eu.etaxonomy.cdm.model.name.BacterialName;
59 import eu.etaxonomy.cdm.model.name.BotanicalName;
60 import eu.etaxonomy.cdm.model.name.HybridRelationship;
61 import eu.etaxonomy.cdm.model.name.NameRelationship;
62 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
63 import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
64 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
65 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
66 import eu.etaxonomy.cdm.model.name.NonViralName;
67 import eu.etaxonomy.cdm.model.name.Rank;
68 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
69 import eu.etaxonomy.cdm.model.name.ZoologicalName;
70 import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
71 import eu.etaxonomy.cdm.model.reference.Reference;
72 import eu.etaxonomy.cdm.model.taxon.Classification;
73 import eu.etaxonomy.cdm.model.taxon.Synonym;
74 import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
75 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
76 import eu.etaxonomy.cdm.model.taxon.Taxon;
77 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
78 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
79 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
80 import eu.etaxonomy.cdm.profiler.ProfilerController;
81 import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
82 import eu.etaxonomy.cdm.strategy.cache.TagEnum;
83 import eu.etaxonomy.cdm.strategy.cache.name.BacterialNameDefaultCacheStrategy;
84 import eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy;
85 import eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy;
86 import eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy;
87 import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;
88
89 /**
90 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
91 * Inserts into DataWarehouse database table <code>Taxon</code>.
92 * It is divided into four phases:<p><ul>
93 * <li>Phase 1: Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.
94 * <li>Phase 2: Export of additional data: ParenTaxonFk and TreeIndex.
95 * <li>Phase 3: Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
96 * <li>Phase 4: Export of Inferred Synonyms.</ul>
97 * @author e.-m.lee
98 * @date 23.02.2010
99 *
100 */
101 @Component
102 public class PesiTaxonExport extends PesiExportBase {
103 private static final Logger logger = Logger.getLogger(PesiTaxonExport.class);
104 private static final Class<? extends CdmBase> standardMethodParameter = TaxonBase.class;
105
106 private static int modCount = 1000;
107 private static final String dbTableName = "Taxon";
108 private static final String dbTableNameSynRel = "RelTaxon";
109 private static final String dbTableAdditionalSourceRel = "AdditionalTaxonSource";
110 private static final String pluralString = "Taxa";
111 private static final String parentPluralString = "Taxa";
112 private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt;
113 private PreparedStatement parentTaxonFkStmt;
114 private PreparedStatement rankTypeExpertsUpdateStmt;
115 private PreparedStatement rankUpdateStmt;
116 private NomenclaturalCode nomenclaturalCode;
117 private Integer kingdomFk;
118 private HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();
119 private List<Rank> rankList = new ArrayList<Rank>();
120 private static final UUID uuidTreeIndex = UUID.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");
121 private AnnotationType treeIndexAnnotationType;
122 private static ExtensionType lastActionExtensionType;
123 private static ExtensionType lastActionDateExtensionType;
124 private static ExtensionType expertNameExtensionType;
125 private static ExtensionType speciesExpertNameExtensionType;
126 private static ExtensionType cacheCitationExtensionType;
127 public static NonViralNameDefaultCacheStrategy<?> zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();
128 public static NonViralNameDefaultCacheStrategy<?> botanicalNameStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
129 public static NonViralNameDefaultCacheStrategy<?> nonViralNameStrategy = NonViralNameDefaultCacheStrategy.NewInstance();
130 public static NonViralNameDefaultCacheStrategy<?> bacterialNameStrategy = BacterialNameDefaultCacheStrategy.NewInstance();
131 private static int currentTaxonId;
132
133
134 /**
135 * @return the treeIndexAnnotationType
136 */
137 protected AnnotationType getTreeIndexAnnotationType() {
138 return treeIndexAnnotationType;
139 }
140
141 /**
142 * @param treeIndexAnnotationType the treeIndexAnnotationType to set
143 */
144 protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType) {
145 this.treeIndexAnnotationType = treeIndexAnnotationType;
146 }
147
148 enum NamePosition {
149 beginning,
150 end,
151 between,
152 alone,
153 nowhere
154 }
155
156 public PesiTaxonExport() {
157 super();
158 }
159
160 /* (non-Javadoc)
161 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
162 */
163 @Override
164 public Class<? extends CdmBase> getStandardMethodParameter() {
165 return standardMethodParameter;
166 }
167
168 /* (non-Javadoc)
169 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
170 */
171 @Override
172 protected boolean doCheck(PesiExportState state) {
173 boolean result = true;
174 return result;
175 }
176
177
178 /* (non-Javadoc)
179 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
180 */
181 @Override
182 protected void doInvoke(PesiExportState state) {
183 try {
184 logger.info("*** Started Making " + pluralString + " ...");
185
186 initPreparedStatements(state);
187
188 // Stores whether this invoke was successful or not.
189 boolean success = true;
190
191 // PESI: Clear the database table Taxon.
192 // doDelete(state);
193
194 // Get specific mappings: (CDM) Taxon -> (PESI) Taxon
195 PesiExportMapping mapping = getMapping();
196 PesiExportMapping synonymRelMapping = getSynRelMapping();
197 PesiExportMapping additionalSourceMapping = getAdditionalSourceMapping(state);
198
199 // Initialize the db mapper
200 mapping.initialize(state);
201 synonymRelMapping.initialize(state);
202 additionalSourceMapping.initialize(state);
203
204 // Find extensionTypes
205 lastActionExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionUuid);
206 lastActionDateExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionDateUuid);
207 expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
208 speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
209 cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.cacheCitationUuid);
210
211 //Export Taxa..
212 success &= doPhase01(state, mapping, additionalSourceMapping);
213
214 //"PHASE 1b: Handle names without taxa ...
215 success &= doNames(state, additionalSourceMapping);
216
217
218 // 2nd Round: Add ParentTaxonFk to each taxon
219 success &= doPhase02(state);
220
221 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
222 success &= doPhase03(state);
223
224 // 4nd Round: Add TreeIndex to each taxon
225 success &= doPhase04(state);
226
227
228 //"PHASE 4: Creating Inferred Synonyms...
229 success &= doPhase05(state, mapping, synonymRelMapping);
230
231 logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
232
233 if (!success){
234 state.setUnsuccessfull();
235 }
236 return;
237 } catch (Exception e) {
238 e.printStackTrace();
239 logger.error(e.getMessage());
240 state.setUnsuccessfull();
241 }
242 }
243
244
245 private void initPreparedStatements(PesiExportState state) throws SQLException {
246 initTreeIndexStatement(state);
247 initRankExpertsUpdateStmt(state);
248 initRankUpdateStatement(state);
249
250 initParentFkStatement(state);
251 }
252
253 // Prepare TreeIndex-And-KingdomFk-Statement
254 private void initTreeIndexStatement(PesiExportState state) throws SQLException {
255 Connection connection = state.getConfig().getDestination().getConnection();
256 String parentTaxonFk_TreeIndex_KingdomFkSql = "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?";
257 parentTaxonFk_TreeIndex_KingdomFkStmt = connection.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql);
258 }
259
260 // Prepare TreeIndex-And-KingdomFk-Statement
261 private void initParentFkStatement(PesiExportState state) throws SQLException {
262 Connection connection = state.getConfig().getDestination().getConnection();
263 String parentTaxonFkSql = "UPDATE Taxon SET ParentTaxonFk = ? WHERE TaxonId = ?";
264 parentTaxonFkStmt = connection.prepareStatement(parentTaxonFkSql);
265 }
266
267 private void initRankUpdateStatement(PesiExportState state) throws SQLException {
268 Connection connection = state.getConfig().getDestination().getConnection();
269 String rankSql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
270 rankUpdateStmt = connection.prepareStatement(rankSql);
271 }
272
273 private void initRankExpertsUpdateStmt(PesiExportState state) throws SQLException {
274 // String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
275 // "ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
276 //TODO handle experts GUIDs
277 Connection connection = state.getConfig().getDestination().getConnection();
278
279 String sql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
280 " WHERE TaxonId = ?";
281 rankTypeExpertsUpdateStmt = connection.prepareStatement(sql);
282 }
283
284 private boolean doPhase01(PesiExportState state, PesiExportMapping mapping, PesiExportMapping additionalSourceMapping) throws SQLException {
285 int count = 0;
286 int pastCount = 0;
287 List<TaxonBase> list;
288 boolean success = true;
289 // Get the limit for objects to save within a single transaction.
290 int limit = state.getConfig().getLimitSave();
291
292
293 logger.info("PHASE 1: Export Taxa...limit is " + limit);
294 // Start transaction
295 TransactionStatus txStatus = startTransaction(true);
296 logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
297
298
299
300 int partitionCount = 0;
301
302 logger.info("Taking snapshot at the beginning of phase 1 of taxonExport");
303 ProfilerController.memorySnapshot();
304 while ((list = getNextTaxonPartition(null, limit, partitionCount++, null)) != null ) {
305
306 logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
307 for (TaxonBase<?> taxon : list) {
308 doCount(count++, modCount, pluralString);
309 TaxonNameBase<?,?> taxonName = taxon.getName();
310 NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
311
312 if (! nvn.isProtectedTitleCache()){
313 nvn.setTitleCache(null, false);
314 }
315 if (! nvn.isProtectedNameCache()){
316 nvn.setNameCache(null, false);
317 }
318 if (! nvn.isProtectedFullTitleCache()){
319 nvn.setFullTitleCache(null, false);
320 }
321 if (! nvn.isProtectedAuthorshipCache()){
322 nvn.setAuthorshipCache(null, false);
323 }
324
325 //core mapping
326 success &= mapping.invoke(taxon);
327 //additional source
328 if (nvn.getNomenclaturalReference() != null || StringUtils.isNotBlank(nvn.getNomenclaturalMicroReference() )){
329 additionalSourceMapping.invoke(taxon);
330 }
331
332 validatePhaseOne(taxon, nvn);
333 taxon = null;
334 nvn = null;
335 taxonName = null;
336
337
338
339 }
340
341
342 // Commit transaction
343 commitTransaction(txStatus);
344 logger.debug("Committed transaction.");
345 logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
346 pastCount = count;
347 /*logger.warn("Taking snapshot at the end of the loop of phase 1 of taxonExport");
348 ProfilerController.memorySnapshot();
349 */
350 // Start transaction
351 txStatus = startTransaction(true);
352 logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
353
354 }
355 if (list == null ) {
356 logger.info("No " + pluralString + " left to fetch.");
357 }
358
359
360
361 // Commit transaction
362 commitTransaction(txStatus);
363 txStatus = null;
364 logger.debug("Committed transaction.");
365 list = null;
366 if (logger.isDebugEnabled()){
367 logger.debug("Taking snapshot at the end of phase 1 of taxonExport");
368 ProfilerController.memorySnapshot();
369 }
370 return success;
371 }
372
373
374 private void validatePhaseOne(TaxonBase<?> taxon, NonViralName taxonName) {
375 // Check whether some rules are violated
376 nomenclaturalCode = taxonName.getNomenclaturalCode();
377 String genusOrUninomial = taxonName.getGenusOrUninomial();
378 String specificEpithet = taxonName.getSpecificEpithet();
379 String infraSpecificEpithet = taxonName.getInfraSpecificEpithet();
380 String infraGenericEpithet = taxonName.getInfraGenericEpithet();
381 Integer rank = getRankFk(taxonName, nomenclaturalCode);
382
383 if (rank == null) {
384 logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
385 } else {
386
387 // Check whether infraGenericEpithet is set correctly
388 // 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
389 // 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
390
391 int ancestorLevel = 0;
392 if (taxonName.getRank().equals(Rank.SUBSPECIES())) {
393 // The accepted taxon two rank levels above should be of rank subgenus
394 ancestorLevel = 2;
395 }
396 if (taxonName.getRank().equals(Rank.SPECIES())) {
397 // The accepted taxon one rank level above should be of rank subgenus
398 ancestorLevel = 1;
399 }
400 if (ancestorLevel > 0) {
401 if (validateAncestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {
402 // The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
403 if (infraGenericEpithet == null) {
404 logger.warn("InfraGenericEpithet does not exist even though it should for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
405 // maybe the taxon could be named here
406 }
407 }
408 }
409
410 if (infraGenericEpithet == null && rank.intValue() == 190) {
411 logger.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
412 }
413 if (specificEpithet != null && rank.intValue() < 216) {
414 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() + ")");
415 }
416 if (infraSpecificEpithet != null && rank.intValue() < 225) {
417 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() + ")";
418 if (StringUtils.isNotBlank(infraSpecificEpithet)){
419 logger.warn(message);
420 }else{
421 logger.warn(message);
422 }
423 }
424 }
425 if (infraSpecificEpithet != null && specificEpithet == null) {
426 logger.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
427 }
428 if (genusOrUninomial == null) {
429 logger.warn("GenusOrUninomial was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
430 }
431 }
432
433
434
435 /**
436 * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists
437 * @param state
438 * @return
439 */
440 private boolean doPhase02(PesiExportState state) {
441 int count = 0;
442 int pastCount = 0;
443 boolean success = true;
444 if (! state.getConfig().isDoParentAndBiota()){
445 logger.info ("Ignore PHASE 2: Make ParentFk and Biota...");
446 return success;
447 }
448
449 List<Taxon> list;
450
451 // Get the limit for objects to save within a single transaction.
452 int limit = state.getConfig().getLimitSave();
453
454 insertBiota(state);
455
456 logger.info("PHASE 2: Make ParentFk and Biota ... limit is " + limit);
457 // Start transaction
458 TransactionStatus txStatus = startTransaction(true);
459 int partitionCount = 0;
460
461 // ProfilerController.memorySnapshot();
462 while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, null)) != null ) {
463
464 logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
465 for (Taxon taxon : list) {
466 for (TaxonNode node : taxon.getTaxonNodes()){
467 doCount(count++, modCount, pluralString);
468 TaxonNode parentNode = node.getParent();
469 if (parentNode != null){
470 int childId = state.getDbId( taxon);
471 int parentId = state.getDbId(parentNode.getTaxon());
472 success &= invokeParentTaxonFk(parentId, childId);
473 }
474 }
475
476 }
477
478 // Commit transaction
479 commitTransaction(txStatus);
480 logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
481 pastCount = count;
482 // Start transaction
483 txStatus = startTransaction(true);
484 logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
485
486 }
487 if (list == null ) {
488 logger.info("No " + pluralString + " left to fetch.");
489 }
490
491 // Commit transaction
492 commitTransaction(txStatus);
493
494 return success;
495
496 }
497
498 /**
499 * Inserts the Biota Taxon if not yet exists.
500 * @param state
501 * @throws SQLException
502 */
503 private void insertBiota(PesiExportState state) {
504 try {
505 ResultSet rs = state.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");
506 if (rs.next() == false){
507 int biotaId = state.getConfig().getNameIdStart() -1 ;
508 String sqlInsertBiota = "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +
509 " VALUES (" + biotaId + ", 0, 0, 'Superdomain', 'Biota', 'Biota', '<i>Biota</i>', 'Biota', '<i>Biota</i>', 1 , 'accepted')";
510 state.getConfig().getDestination().update(sqlInsertBiota);
511 }
512 } catch (SQLException e) {
513 logger.warn ("Biota could not be requested or inserted");
514 }
515 }
516
517 // 4th round: Add TreeIndex to each taxon
518 private boolean doPhase04(PesiExportState state) {
519 boolean success = true;
520
521 logger.info("PHASE 4: Make TreeIndex ... ");
522
523 //TODO test if possible to move to phase 02
524 String sql = " UPDATE Taxon SET ParentTaxonFk = (Select TaxonId from Taxon where RankFk = 0) " +
525 " WHERE (RankFk = 10) and TaxonStatusFk = 1 ";
526 state.getConfig().getDestination().update(sql);
527
528 state.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
529
530 return success;
531
532 }
533
534
535 // 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
536 private boolean doPhase02_OLD(PesiExportState state) {
537 boolean success = true;
538 if (! state.getConfig().isDoTreeIndex()){
539 logger.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
540 return success;
541 }
542
543 List<Classification> classificationList = null;
544 logger.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
545
546 // Specify starting ranks for tree traversing
547 rankList.add(Rank.KINGDOM());
548 rankList.add(Rank.GENUS());
549
550 // Specify where to stop traversing (value) when starting at a specific Rank (key)
551 rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
552 rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
553
554 StringBuffer treeIndex = new StringBuffer();
555
556 // Retrieve list of classifications
557 TransactionStatus txStatus = startTransaction(true);
558 logger.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
559 classificationList = getClassificationService().listClassifications(null, 0, null, null);
560 commitTransaction(txStatus);
561 logger.debug("Committed transaction.");
562
563 logger.info("Fetched " + classificationList.size() + " classification(s).");
564
565 setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex, "TreeIndex", "TreeIndex", "TI"));
566 List<TaxonNode> rankSpecificRootNodes;
567 for (Classification classification : classificationList) {
568 for (Rank rank : rankList) {
569
570 txStatus = startTransaction(true);
571 logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
572
573 rankSpecificRootNodes = getClassificationService().loadRankSpecificRootNodes(classification, rank, null, null, null);
574 logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
575
576 commitTransaction(txStatus);
577 logger.debug("Committed transaction.");
578
579 for (TaxonNode rootNode : rankSpecificRootNodes) {
580 txStatus = startTransaction(false);
581 Rank endRank = rank2endRankMap.get(rank);
582 if (endRank != null) {
583 logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");
584 } else {
585 logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");
586 }
587
588 TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
589
590 if (isPesiTaxon(newNode.getTaxon())){
591 TaxonNode parentNode = newNode.getParent();
592 if (rank.equals(Rank.KINGDOM())) {
593 treeIndex = new StringBuffer();
594 treeIndex.append("#");
595 } else {
596 // Get treeIndex from parentNode
597 if (parentNode != null) {
598 boolean annotationFound = false;
599 Set<Annotation> annotations = parentNode.getAnnotations();
600 for (Annotation annotation : annotations) {
601 AnnotationType annotationType = annotation.getAnnotationType();
602 if (annotationType != null && annotationType.equals(getTreeIndexAnnotationType())) {
603 treeIndex = new StringBuffer(CdmUtils.Nz(annotation.getText()));
604 annotationFound = true;
605 // logger.error("treeIndex: " + treeIndex);
606 break;
607 }
608 }
609 if (!annotationFound) {
610 // This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
611 logger.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode.getUuid() + ", Taxon: " + parentNode.getTaxon().getUuid());
612 treeIndex = new StringBuffer();
613 treeIndex.append("#");
614 }
615 } else {
616 // TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
617 logger.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode.getUuid());
618 treeIndex = new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
619 treeIndex.append("#");
620 }
621 }
622 nomenclaturalCode = newNode.getTaxon().getName().getNomenclaturalCode();
623 kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
624 traverseTree(newNode, parentNode, treeIndex, endRank, state);
625 parentNode =null;
626 }else{
627 logger.debug("Taxon is not a PESI taxon: " + newNode.getTaxon().getUuid());
628 }
629
630 newNode = null;
631
632 try {
633 commitTransaction(txStatus);
634 logger.debug("Committed transaction.");
635 } catch (Exception e) {
636 logger.error(e.getMessage());
637 e.printStackTrace();
638 }
639
640 }
641 rankSpecificRootNodes = null;
642 }
643
644 }
645
646 logger.warn("Taking snapshot at the end of phase 2 of taxonExport");
647 ProfilerController.memorySnapshot();
648 return success;
649 }
650
651 //PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
652 private boolean doPhase03(PesiExportState state) {
653 int count = 0;
654 int pastCount = 0;
655 boolean success = true;
656 if (! state.getConfig().isDoTreeIndex()){
657 logger.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
658 return success;
659 }
660 // Get the limit for objects to save within a single transaction.
661 int limit = state.getConfig().getLimitSave();
662
663 List<TaxonBase> list;
664 logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
665 // Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
666
667 // Start transaction
668 TransactionStatus txStatus = startTransaction(true);
669 logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
670 int partitionCount = 0;
671 while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {
672
673 logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
674 for (TaxonBase<?> taxon : list) {
675 TaxonNameBase<?,?> taxonName = taxon.getName();
676 // Determine expertFk
677 // Integer expertFk = makeExpertFk(state, taxonName);
678 //
679 // // Determine speciesExpertFk
680 // Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
681
682 doCount(count++, modCount, pluralString);
683 Integer typeNameFk = getTypeNameFk(taxonName, state);
684 kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
685
686 //TODO why are expertFks needed? (Andreas M.)
687 // if (expertFk != null || speciesExpertFk != null) {
688 invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon),
689 typeNameFk, kingdomFk, state);
690 // }
691
692 taxon = null;
693 taxonName = null;
694 }
695
696 // Commit transaction
697 commitTransaction(txStatus);
698 logger.debug("Committed transaction.");
699 logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
700 pastCount = count;
701
702 // Start transaction
703 txStatus = startTransaction(true);
704 logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
705 }
706 if (list == null) {
707 logger.info("No " + pluralString + " left to fetch.");
708 }
709
710 list = null;
711
712 // Commit transaction
713 commitTransaction(txStatus);
714
715 logger.debug("Committed transaction.");
716 logger.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount);
717 ProfilerController.memorySnapshot();
718 return success;
719 }
720
721 // "PHASE 5: Creating Inferred Synonyms..."
722 private boolean doPhase05(PesiExportState state, PesiExportMapping mapping, PesiExportMapping synRelMapping) throws SQLException {
723 int count;
724 int pastCount;
725 boolean success = true;
726 // Get the limit for objects to save within a single transaction.
727 if (! state.getConfig().isDoInferredSynonyms()){
728 logger.info ("Ignore PHASE 5: Creating Inferred Synonyms...");
729 return success;
730 }
731
732 int limit = state.getConfig().getLimitSave();
733 // Create inferred synonyms for accepted taxa
734 logger.info("PHASE 4: Creating Inferred Synonyms...");
735
736 // Determine the count of elements in datawarehouse database table Taxon
737 currentTaxonId = determineTaxonCount(state);
738 currentTaxonId++;
739
740 count = 0;
741 pastCount = 0;
742 int pageSize = limit;
743 int pageNumber = 1;
744 String inferredSynonymPluralString = "Inferred Synonyms";
745
746 // Start transaction
747 TransactionStatus txStatus = startTransaction(true);
748 logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
749 List<TaxonBase> taxonList = null;
750
751
752
753 while ((taxonList = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SPECIES(), pageSize, pageNumber)).size() > 0) {
754 HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
755
756 logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
757 inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
758 synRelMapping, taxonList));
759
760 doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
761 // Commit transaction
762 commitTransaction(txStatus);
763 logger.debug("Committed transaction.");
764 logger.info("Exported " + (taxonList.size()) + " " + inferredSynonymPluralString + ". Total: " + count);
765 //pastCount = count;
766
767 // Save Rank Data and KingdomFk for inferred synonyms
768 for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
769 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);
770 }
771
772 // Start transaction
773 txStatus = startTransaction(true);
774 logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
775
776 // Increment pageNumber
777 pageNumber++;
778 }
779
780 while ((taxonList = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SUBSPECIES(), pageSize, pageNumber)).size() > 0) {
781 HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
782
783 logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
784 inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
785 synRelMapping, taxonList));
786 ;
787 doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
788 // Commit transaction
789 commitTransaction(txStatus);
790 logger.debug("Committed transaction.");
791 logger.info("Exported " + taxonList.size()+ " " + inferredSynonymPluralString + ". Total: " + count);
792 //pastCount = count;
793
794 // Save Rank Data and KingdomFk for inferred synonyms
795 for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
796 invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);
797 }
798
799 // Start transaction
800 txStatus = startTransaction(true);
801 logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
802
803 // Increment pageNumber
804 pageNumber++;
805 }
806 if (taxonList.size() == 0) {
807 logger.info("No " + parentPluralString + " left to fetch.");
808 }
809
810 taxonList = null;
811 // logger.warn("Taking snapshot at the end of phase 4 of taxonExport");
812 // ProfilerController.memorySnapshot();
813
814 // Commit transaction
815 commitTransaction(txStatus);
816 System.gc();
817 logger.debug("Taking snapshot at the end of phase 4 after gc() of taxonExport");
818 ProfilerController.memorySnapshot();
819 logger.debug("Committed transaction.");
820 return success;
821 }
822
823 /**
824 * @param state
825 * @param mapping
826 * @param synRelMapping
827 * @param currentTaxonId
828 * @param taxonList
829 * @param inferredSynonymsDataToBeSaved
830 * @return
831 */
832 private HashMap<Integer, TaxonNameBase<?, ?>> createInferredSynonymsForTaxonList(PesiExportState state,
833 PesiExportMapping mapping, PesiExportMapping synRelMapping, List<TaxonBase> taxonList) {
834
835 Taxon acceptedTaxon;
836 Classification classification = null;
837 List<Synonym> inferredSynonyms = null;
838 boolean localSuccess = true;
839
840 HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
841
842 for (TaxonBase<?> taxonBase : taxonList) {
843
844 if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
845 acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
846 TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
847
848 if (taxonName.isInstanceOf(ZoologicalName.class)) {
849 nomenclaturalCode = taxonName.getNomenclaturalCode();
850 kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
851
852 Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();
853 TaxonNode singleNode = null;
854
855 if (taxonNodes.size() > 0) {
856 // Determine the classification of the current TaxonNode
857
858 singleNode = taxonNodes.iterator().next();
859 if (singleNode != null) {
860 classification = singleNode.getClassification();
861 } else {
862 logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");
863 }
864 } else {
865 // Classification could not be determined directly from this TaxonNode
866 // The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
867 if (taxonNodes.size() == 0) {
868 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");
869
870 }
871 }
872
873 if (classification != null) {
874 try{
875 TaxonNameBase name = acceptedTaxon.getName();
876 //if (name.isSpecies() || name.isInfraSpecific()){
877 inferredSynonyms = getTaxonService().createAllInferredSynonyms(acceptedTaxon, classification, true);
878 //}
879 // inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
880 if (inferredSynonyms != null) {
881 for (Synonym synonym : inferredSynonyms) {
882 // TaxonNameBase<?,?> synonymName = synonym.getName();
883 MarkerType markerType =getUuidMarkerType(PesiTransformer.uuidMarkerGuidIsMissing, state);
884 synonym.addMarker(Marker.NewInstance(markerType, true));
885 // Both Synonym and its TaxonName have no valid Id yet
886 synonym.setId(currentTaxonId++);
887
888
889 localSuccess &= mapping.invoke(synonym);
890 //get SynonymRelationship and export
891 if (synonym.getSynonymRelations().isEmpty() ){
892 SynonymRelationship synRel;
893 IdentifiableSource source = synonym.getSources().iterator().next();
894 if (source.getIdNamespace().contains("Potential combination")){
895 synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
896 logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to potential combination");
897 } else if (source.getIdNamespace().contains("Inferred Genus")){
898 synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_GENUS_OF());
899 logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred genus");
900 } else if (source.getIdNamespace().contains("Inferred Epithet")){
901 synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_EPITHET_OF());
902 logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred epithet");
903 } else{
904 synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_SYNONYM_OF());
905 logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred synonym");
906 }
907
908 localSuccess &= synRelMapping.invoke(synRel);
909 if (!localSuccess) {
910 logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
911 }
912 synRel = null;
913 } else {
914 for (SynonymRelationship synRel: synonym.getSynonymRelations()){
915 localSuccess &= synRelMapping.invoke(synRel);
916 if (!localSuccess) {
917 logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
918 } else {
919 logger.info("Synonym relationship successfully exported: " + synonym.getTitleCache() + " " +acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
920 }
921 synRel = null;
922 }
923 }
924
925 inferredSynonymsDataToBeSaved.put(synonym.getId(), synonym.getName());
926 }
927 }
928 }catch(Exception e){
929 logger.error(e.getMessage());
930 e.printStackTrace();
931 }
932 } else {
933 logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");
934 }
935 } else {
936 // logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
937 }
938 } else {
939 logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");
940 }
941 }
942 return inferredSynonymsDataToBeSaved;
943 }
944
945
946 /**
947 * Handles names that do not appear in taxa
948 * @param state
949 * @param mapping
950 * @return
951 */
952 private boolean doNames(PesiExportState state, PesiExportMapping additionalSourceMapping) throws SQLException {
953
954 boolean success = true;
955 if (! state.getConfig().isDoPureNames()){
956 logger.info ("Ignore PHASE 1b: PureNames");
957 return success;
958 }
959
960 try {
961 PesiExportMapping mapping = getPureNameMapping(state);
962 mapping.initialize(state);
963 int count = 0;
964 int pastCount = 0;
965 List<NonViralName<?>> list;
966 success = true;
967 // Get the limit for objects to save within a single transaction.
968 int limit = state.getConfig().getLimitSave();
969
970
971 logger.info("PHASE 1b: Export Pure Names ...");
972 // Start transaction
973 TransactionStatus txStatus = startTransaction(true);
974 logger.info("Started new transaction for Pure Names. Fetching some " + pluralString + " (max: " + limit + ") ...");
975
976 int partitionCount = 0;
977 while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null ) {
978
979 logger.info("Fetched " + list.size() + " names without taxa. Exporting...");
980 for (TaxonNameBase<?,?> taxonName : list) {
981 doCount(count++, modCount, pluralString);
982 success &= mapping.invoke(taxonName);
983 //additional source
984 if (taxonName.getNomenclaturalReference() != null || StringUtils.isNotBlank(taxonName.getNomenclaturalMicroReference() )){
985 additionalSourceMapping.invoke(taxonName);
986 }
987 }
988
989 // Commit transaction
990 commitTransaction(txStatus);
991 logger.debug("Committed transaction.");
992 logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
993 pastCount = count;
994
995 // Start transaction
996 txStatus = startTransaction(true);
997 logger.info("Started new transaction for PureNames. Fetching some " + pluralString + " (max: " + limit + ") ...");
998 }
999 if (list == null) {
1000 logger.info("No " + pluralString + " left to fetch.");
1001 }
1002 // Commit transaction
1003 commitTransaction(txStatus);
1004 logger.debug("Committed transaction.");
1005 } catch (Exception e) {
1006 logger.error("Error occurred in pure name export");
1007 e.printStackTrace();
1008 success = false;
1009 }
1010 return success;
1011 }
1012
1013 /**
1014 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
1015 * @param state The {@link PesiExportState PesiExportState}.
1016 * @return The count.
1017 */
1018 private Integer determineTaxonCount(PesiExportState state) {
1019 Integer result = null;
1020 PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
1021
1022 String sql;
1023 Source destination = pesiConfig.getDestination();
1024 sql = "SELECT max(taxonId) FROM Taxon";
1025 destination.setQuery(sql);
1026 ResultSet resultSet = destination.getResultSet();
1027 try {
1028 resultSet.next();
1029 result = resultSet.getInt(1);
1030 } catch (SQLException e) {
1031 logger.error("TaxonCount could not be determined: " + e.getMessage());
1032 e.printStackTrace();
1033 }
1034 return result;
1035 }
1036
1037 /**
1038 * Checks whether a parent at specific level has a specific Rank.
1039 * @param taxonName A {@link TaxonNameBase TaxonName}.
1040 * @param level The ancestor level.
1041 * @param ancestorRank The ancestor rank.
1042 * @return Whether a parent at a specific level has a specific Rank.
1043 */
1044 private boolean validateAncestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {
1045 boolean result = false;
1046 TaxonNode parentNode = null;
1047 if (taxonBase.isInstanceOf(Taxon.class)){
1048 Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1049 // Get ancestor Taxon via TaxonNode
1050 Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
1051 if (taxonNodes.size() == 1) {
1052 TaxonNode taxonNode = taxonNodes.iterator().next();
1053 if (taxonNode != null) {
1054 for (int i = 0; i < level; i++) {
1055 if (taxonNode != null) {
1056 taxonNode = taxonNode.getParent();
1057 }
1058 }
1059 parentNode = taxonNode;
1060 }
1061 } else if (taxonNodes.size() > 1) {
1062 logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1063 }
1064 }
1065 //compare
1066 if (parentNode != null) {
1067 TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);
1068 Taxon parentTaxon = node.getTaxon();
1069 if (parentTaxon != null) {
1070 TaxonNameBase<?,?> parentTaxonName = parentTaxon.getName();
1071 if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {
1072 result = true;
1073 }
1074 } else {
1075 logger.error("This TaxonNode has no Taxon: " + node.getUuid());
1076 }
1077 }
1078 return result;
1079 }
1080
1081 /**
1082 * Returns the AnnotationType for a given UUID.
1083 * @param uuid The Annotation UUID.
1084 * @param label The Annotation label.
1085 * @param text The Annotation text.
1086 * @param labelAbbrev The Annotation label abbreviation.
1087 * @return The AnnotationType.
1088 */
1089 protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){
1090 AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);
1091 if (annotationType == null) {
1092 annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
1093 annotationType.setUuid(uuid);
1094 // annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1095 getTermService().save(annotationType);
1096 }
1097 return annotationType;
1098 }
1099
1100 /**
1101 * Traverses the classification recursively and stores determined values for every Taxon.
1102 * @param childNode The {@link TaxonNode TaxonNode} to process.
1103 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1104 * @param treeIndex The TreeIndex at the current level.
1105 * @param fetchLevel Rank to stop fetching at.
1106 * @param state The {@link PesiExportState PesiExportState}.
1107 */
1108 private void traverseTree(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, Rank fetchLevel, PesiExportState state) {
1109 // Traverse all branches from this childNode until specified fetchLevel is reached.
1110 StringBuffer localTreeIndex = new StringBuffer(treeIndex);
1111 Taxon childTaxon = childNode.getTaxon();
1112 if (childTaxon != null) {
1113 if (isPesiTaxon(childTaxon)){
1114 Integer taxonId = state.getDbId(childTaxon);
1115 TaxonNameBase<?,?> childName = childTaxon.getName();
1116 if (taxonId != null) {
1117 Rank childRank = childName.getRank();
1118 if (childRank != null) {
1119 if (! childRank.equals(fetchLevel)) {
1120
1121 localTreeIndex.append(taxonId + "#");
1122
1123 saveData(childNode, parentNode, localTreeIndex, state, taxonId);
1124
1125 // Store treeIndex as annotation for further use
1126 Annotation annotation = Annotation.NewInstance(localTreeIndex.toString(), getTreeIndexAnnotationType(), Language.DEFAULT());
1127 childNode.addAnnotation(annotation);
1128
1129 for (TaxonNode newNode : childNode.getChildNodes()) {
1130 if (newNode.getTaxon() != null && isPesiTaxon(newNode.getTaxon())){
1131 traverseTree(newNode, childNode, localTreeIndex, fetchLevel, state);
1132 }
1133 }
1134
1135 } else {
1136 // logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1137 return;
1138 }
1139 } else {
1140 logger.error("Rank is NULL. FetchLevel can not be checked: " + childName.getUuid() + " (" + childName.getTitleCache() + ")");
1141 }
1142 } else {
1143 logger.error("Taxon can not be found in state: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
1144 }
1145 }else{
1146 if (logger.isDebugEnabled()){
1147 logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
1148 }
1149 }
1150
1151 } else {
1152 logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
1153 }
1154 }
1155
1156 /**
1157 * Stores values in database for every recursive round.
1158 * @param childNode The {@link TaxonNode TaxonNode} to process.
1159 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1160 * @param treeIndex The TreeIndex at the current level.
1161 * @param state The {@link PesiExportState PesiExportState}.
1162 * @param currentTaxonFk The TaxonFk to store the values for.
1163 */
1164 private void saveData(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, PesiExportState state, Integer currentTaxonFk) {
1165 // We are differentiating kingdoms by the nomenclatural code for now.
1166 // This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1167 Taxon childTaxon = childNode.getTaxon();
1168 if (isPesiTaxon(childTaxon)) {
1169 TaxonBase<?> parentTaxon = null;
1170 if (parentNode != null) {
1171 parentTaxon = parentNode.getTaxon();
1172
1173 }
1174
1175 invokeParentTaxonFkAndTreeIndex(state.getDbId(parentTaxon), currentTaxonFk, treeIndex);
1176 }
1177
1178 }
1179
1180 /**
1181 * Inserts values into the Taxon database table.
1182 * @param taxonName The {@link TaxonNameBase TaxonName}.
1183 * @param state The {@link PesiExportState PesiExportState}.
1184 * @param stmt The prepared statement.
1185 * @return Whether save was successful or not.
1186 */
1187 protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk, Integer currentTaxonFk, StringBuffer treeIndex) {
1188 try {
1189 if (parentTaxonFk != null) {
1190 parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(1, parentTaxonFk);
1191 } else {
1192 parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(1, null);
1193 }
1194
1195 if (treeIndex != null) {
1196 parentTaxonFk_TreeIndex_KingdomFkStmt.setString(2, treeIndex.toString());
1197 } else {
1198 parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(2, null);
1199 }
1200
1201 if (currentTaxonFk != null) {
1202 parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(3, currentTaxonFk);
1203 } else {
1204 parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(3, null);
1205 }
1206
1207 parentTaxonFk_TreeIndex_KingdomFkStmt.executeUpdate();
1208 return true;
1209 } catch (SQLException e) {
1210 logger.error("ParentTaxonFk (" + parentTaxonFk ==null? "-":parentTaxonFk + ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk == null? "-" :currentTaxonFk) + ": " + e.getMessage());
1211 e.printStackTrace();
1212 return false;
1213 }
1214 }
1215
1216 protected boolean invokeParentTaxonFk(Integer parentId, Integer childId) {
1217 try {
1218 parentTaxonFkStmt.setInt(1, parentId);
1219 parentTaxonFkStmt.setInt(2, childId);
1220 parentTaxonFkStmt.executeUpdate();
1221 return true;
1222 } catch (SQLException e) {
1223 logger.warn("ParentTaxonFk (" + parentId ==null? "-":parentId + ") could not be inserted into database for taxon "+ (childId == null? "-" :childId) + ": " + e.getMessage());
1224 e.printStackTrace();
1225 return false;
1226 }
1227 }
1228
1229
1230 /**
1231 * Inserts Rank data and KingdomFk into the Taxon database table.
1232 * @param taxonName The {@link TaxonNameBase TaxonName}.
1233 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1234 * @param taxonFk The TaxonFk to store the values for.
1235 * @param state
1236 * @param kindomFk The KingdomFk.
1237 * @return Whether save was successful or not.
1238 */
1239 private boolean invokeRankDataAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, Integer taxonFk, Integer kingdomFk, PesiExportState state) {
1240 try {
1241 Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1242 if (rankFk != null) {
1243 rankUpdateStmt.setInt(1, rankFk);
1244 } else {
1245 rankUpdateStmt.setObject(1, null);
1246 }
1247
1248 String rankCache = getRankCache(taxonName, nomenclaturalCode, state);
1249 if (rankCache != null) {
1250 rankUpdateStmt.setString(2, rankCache);
1251 } else {
1252 rankUpdateStmt.setObject(2, null);
1253 }
1254
1255 if (kingdomFk != null) {
1256 rankUpdateStmt.setInt(3, kingdomFk);
1257 } else {
1258 rankUpdateStmt.setObject(3, null);
1259 }
1260
1261 if (taxonFk != null) {
1262 rankUpdateStmt.setInt(4, taxonFk);
1263 } else {
1264 rankUpdateStmt.setObject(4, null);
1265 }
1266
1267 rankUpdateStmt.executeUpdate();
1268 return true;
1269 } catch (SQLException e) {
1270 logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());
1271 e.printStackTrace();
1272 return false;
1273 }
1274 }
1275
1276 /**
1277 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1278 * @param taxonName The {@link TaxonNameBase TaxonName}.
1279 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1280 * @param taxonFk The TaxonFk to store the values for.
1281 * @param typeNameFk The TypeNameFk.
1282 * @param state
1283 * @param kindomFk The KingdomFk.
1284 * @param expertFk The ExpertFk.
1285 * @param speciesExpertFk The SpeciesExpertFk.
1286 * @return Whether save was successful or not.
1287 */
1288 private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode,
1289 Integer taxonFk, Integer typeNameFk, Integer kingdomFkk, PesiExportState state) {
1290 try {
1291 int index = 1;
1292 Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1293 if (rankFk != null) {
1294 rankTypeExpertsUpdateStmt.setInt(index++, rankFk);
1295 } else {
1296 rankTypeExpertsUpdateStmt.setObject(index++, null);
1297 }
1298
1299 String rankCache = getRankCache(taxonName, nomenclaturalCode, state);
1300 if (rankCache != null) {
1301 rankTypeExpertsUpdateStmt.setString(index++, rankCache);
1302 } else {
1303 rankTypeExpertsUpdateStmt.setObject(index++, null);
1304 }
1305
1306 if (typeNameFk != null) {
1307 rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);
1308 } else {
1309 rankTypeExpertsUpdateStmt.setObject(index++, null);
1310 }
1311
1312 if (kingdomFk != null) {
1313 rankTypeExpertsUpdateStmt.setInt(index++, kingdomFk);
1314 } else {
1315 rankTypeExpertsUpdateStmt.setObject(index++, null);
1316 }
1317
1318 // if (expertFk != null) {
1319 // rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1320 // } else {
1321 // rankTypeExpertsUpdateStmt.setObject(5, null);
1322 // }
1323 //
1324 // //TODO handle experts GUIDS
1325 // if (speciesExpertFk != null) {
1326 // rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1327 // } else {
1328 // rankTypeExpertsUpdateStmt.setObject(6, null);
1329 // }
1330 //
1331 if (taxonFk != null) {
1332 rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);
1333 } else {
1334 rankTypeExpertsUpdateStmt.setObject(index++, null);
1335 }
1336
1337 rankTypeExpertsUpdateStmt.executeUpdate();
1338 return true;
1339 } catch (SQLException e) {
1340 logger.error("Data could not be inserted into database: " + e.getMessage());
1341 e.printStackTrace();
1342 return false;
1343 } catch (Exception e) {
1344 logger.error("Some exception occurred: " + e.getMessage());
1345 e.printStackTrace();
1346 return false;
1347 }
1348 }
1349
1350 /**
1351 * Deletes all entries of database tables related to <code>Taxon</code>.
1352 * @param state The {@link PesiExportState PesiExportState}.
1353 * @return Whether the delete operation was successful or not.
1354 */
1355 protected boolean doDelete(PesiExportState state) {
1356 PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
1357
1358 String sql;
1359 Source destination = pesiConfig.getDestination();
1360
1361 // Clear Taxon
1362 sql = "DELETE FROM " + dbTableName;
1363 destination.setQuery(sql);
1364 destination.update(sql);
1365 return true;
1366 }
1367
1368 /* (non-Javadoc)
1369 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1370 */
1371 @Override
1372 protected boolean isIgnore(PesiExportState state) {
1373 return ! state.getConfig().isDoTaxa();
1374 }
1375
1376
1377 /**
1378 * Creates the kingdom fk.
1379 * @param taxonName
1380 * @return
1381 */
1382 @SuppressWarnings("unused") //used by mapper
1383 private static Integer getKingdomFk(TaxonNameBase taxonName){
1384 return PesiTransformer.nomenClaturalCode2Kingdom(taxonName.getNomenclaturalCode());
1385 }
1386
1387 /**
1388 * Creates the parent fk.
1389 * @param taxonName
1390 * @return
1391 */
1392 @SuppressWarnings("unused") //used by mapper
1393 private static Integer getParentTaxonFk(TaxonBase<?> taxonBase, PesiExportState state){
1394 if (taxonBase.isInstanceOf(Taxon.class)){
1395 Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1396 if (! isMisappliedName(taxon)){
1397 Set<TaxonNode> nodes = taxon.getTaxonNodes();
1398 if (nodes.size() == 0){
1399 if (taxon.getName().getRank().isLower(Rank.KINGDOM())){
1400 logger.warn("Accepted taxon has no parent. " + taxon.getTitleCache() + ", " + taxon.getUuid());
1401 }
1402 }else if (nodes.size() > 1){
1403 logger.warn("Taxon has more than 1 node attached. This is not supported by PESI export." + taxon.getTitleCache() + ", " + taxon.getUuid());
1404 }else{
1405 Taxon parent =nodes.iterator().next().getParent().getTaxon();
1406 return state.getDbId(parent);
1407 }
1408 }
1409 }
1410 return null;
1411 }
1412
1413 /**
1414 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1415 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1416 * @param taxonName
1417 * @return
1418 */
1419 @SuppressWarnings("unused") //used by mapper
1420 private static Integer getRankFk(TaxonNameBase<?,?> taxonName) {
1421 return getRankFk(taxonName, taxonName.getNomenclaturalCode());
1422 }
1423
1424
1425 /**
1426 * Returns the <code>RankFk</code> attribute.
1427 * @param taxonName The {@link TaxonNameBase TaxonName}.
1428 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1429 * @return The <code>RankFk</code> attribute.
1430 * @see MethodMapper
1431 */
1432 private static Integer getRankFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1433 Integer result = null;
1434 try {
1435 if (nomenclaturalCode != null) {
1436 if (taxonName != null) {
1437 if (taxonName.getRank() == null) {
1438 logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1439 } else {
1440 result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1441 }
1442 if (result == null) {
1443 logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1444 }
1445 }
1446 }
1447 } catch (Exception e) {
1448 e.printStackTrace();
1449 }
1450 return result;
1451 }
1452
1453 /**
1454 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1455 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1456 * @param taxonName
1457 * @return
1458 */
1459 @SuppressWarnings("unused") //used by mapper
1460 private static String getRankCache(TaxonNameBase<?,?> taxonName, PesiExportState state) {
1461 return getRankCache(taxonName, taxonName.getNomenclaturalCode(), state);
1462 }
1463
1464
1465 /**
1466 * Returns the <code>RankCache</code> attribute.
1467 * @param taxonName The {@link TaxonNameBase TaxonName}.
1468 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1469 * @param state
1470 * @return The <code>RankCache</code> attribute.
1471 * @see MethodMapper
1472 */
1473 private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, PesiExportState state) {
1474 if (nomenclaturalCode != null) {
1475 return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1476 }else{
1477 logger.warn("No nomenclatural code defined for name " + taxonName.getUuid());
1478 return null;
1479 }
1480
1481 }
1482
1483
1484 /**
1485 * Returns the <code>DisplayName</code> attribute.
1486 * @param taxon The {@link TaxonBase Taxon}.
1487 * @return The <code>DisplayName</code> attribute.
1488 * @see MethodMapper
1489 */
1490 @SuppressWarnings("unused") //used by Mapper
1491 private static String getDisplayName(TaxonBase<?> taxon) {
1492 TaxonNameBase<?,?> taxonName = taxon.getName();
1493 String result = getDisplayName(taxonName);
1494 if (isMisappliedName(taxon)){
1495 result = result + " " + getAuthorString(taxon);
1496 }
1497 return result;
1498 }
1499
1500 /**
1501 * Returns the <code>AuthorString</code> attribute.
1502 * @param taxonName The {@link TaxonNameBase TaxonName}.
1503 * @return The <code>AuthorString</code> attribute.
1504 * @see MethodMapper
1505 */
1506 @SuppressWarnings("unused") //used by mapper
1507 protected static String getAuthorString(TaxonBase<?> taxon) {
1508 try {
1509 String result = null;
1510 boolean isNonViralName = false;
1511 String authorshipCache = null;
1512 TaxonNameBase<?,?> taxonName = taxon.getName();
1513 if (taxonName != null && taxonName.isInstanceOf(NonViralName.class)){
1514 authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();
1515 isNonViralName = true;
1516 }
1517 result = authorshipCache;
1518
1519 // For a misapplied names there are special rules
1520 if (isMisappliedName(taxon)){
1521 if (taxon.getSec() != null){
1522 String secTitle = taxon.getSec().getTitleCache();
1523 if (! secTitle.startsWith("auct")){
1524 secTitle = "sensu " + secTitle;
1525 }else if (secTitle.equals("auct")){ //may be removed once the title cache is generated correctly for references with title auct. #
1526 secTitle = "auct.";
1527 }
1528 return secTitle;
1529 }else if (StringUtils.isBlank(authorshipCache)) {
1530 // Set authorshipCache to "auct."
1531 result = PesiTransformer.AUCT_STRING;
1532 }else{
1533 result = PesiTransformer.AUCT_STRING;
1534 // result = authorshipCache;
1535 }
1536 }
1537
1538 if (taxonName == null){
1539 logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1540 }else if (! isNonViralName){
1541 logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1542 }
1543
1544 if (StringUtils.isBlank(result)) {
1545 return null;
1546 } else {
1547 return result;
1548 }
1549 } catch (Exception e) {
1550 e.printStackTrace();
1551 return null;
1552 }
1553
1554 }
1555
1556
1557 /**
1558 * Returns the <code>DisplayName</code> attribute.
1559 * @param taxonName The {@link TaxonNameBase TaxonName}.
1560 * @return The <code>DisplayName</code> attribute.
1561 * @see MethodMapper
1562 */
1563 @SuppressWarnings("unused") //used by Mapper
1564 private static String getDisplayName(TaxonNameBase<?,?> taxonName) {
1565 // TODO: extension?
1566 if (taxonName == null) {
1567 return null;
1568 }else{
1569 INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1570 HTMLTagRules tagRules = new HTMLTagRules().
1571 addRule(TagEnum.name, "i").
1572 addRule(TagEnum.nomStatus, "@status@");
1573
1574 NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1575 String result = cacheStrategy.getFullTitleCache(nvn, tagRules);
1576 cacheStrategy = null;
1577 nvn = null;
1578 return result.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");
1579 }
1580 }
1581
1582
1583 /**
1584 * Returns the <code>WebShowName</code> attribute for a taxon.
1585 * @param taxonName The {@link TaxonNameBase TaxonName}.
1586 * @return The <code>WebShowName</code> attribute.
1587 * @see MethodMapper
1588 */
1589 @SuppressWarnings("unused")
1590 private static String getWebShowName(TaxonBase<?> taxon) {
1591 TaxonNameBase<?,?> taxonName = taxon.getName();
1592 String result = getWebShowName(taxonName);
1593 if (isMisappliedName(taxon)){
1594 result = result + " " + getAuthorString(taxon);
1595 }
1596 return result;
1597 }
1598
1599 /**
1600 * Returns the <code>WebShowName</code> attribute.
1601 * @param taxonName The {@link TaxonNameBase TaxonName}.
1602 * @return The <code>WebShowName</code> attribute.
1603 * @see MethodMapper
1604 */
1605 private static String getWebShowName(TaxonNameBase<?,?> taxonName) {
1606 //TODO extensions?
1607 if (taxonName == null) {
1608 return null;
1609 }else{
1610 INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1611
1612 HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");
1613 NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1614 String result = cacheStrategy.getTitleCache(nvn, tagRules);
1615 cacheStrategy = null;
1616 nvn = null;
1617 return result;
1618 }
1619 }
1620
1621
1622 /**
1623 * Returns the <code>WebSearchName</code> attribute.
1624 * @param taxonName The {@link NonViralName NonViralName}.
1625 * @return The <code>WebSearchName</code> attribute.
1626 * @see MethodMapper
1627 */
1628 @SuppressWarnings("unused")
1629 private static String getWebSearchName(TaxonNameBase<?,?> taxonName) {
1630 //TODO extensions?
1631 NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1632 NonViralNameDefaultCacheStrategy<NonViralName<?>> strategy = getCacheStrategy(nvn);
1633 String result = strategy.getNameCache(nvn);
1634 strategy = null;
1635 nvn = null;
1636 return result;
1637 }
1638
1639
1640 /**
1641 * Returns the <code>FullName</code> attribute.
1642 * @param taxonName The {@link NonViralName NonViralName}.
1643 * @return The <code>FullName</code> attribute.
1644 * @see MethodMapper
1645 */
1646 @SuppressWarnings("unused")
1647 private static String getFullName(TaxonNameBase taxonName) {
1648 //TODO extensions?
1649 NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1650 String result = getCacheStrategy(nvn).getTitleCache(nvn);
1651 Iterator<TaxonBase> taxa = taxonName.getTaxa().iterator();
1652 if (taxonName.getTaxa().size() >0){
1653 if (taxonName.getTaxa().size() == 1){
1654 TaxonBase taxon = taxa.next();
1655 if (isMisappliedName(taxon)){
1656 result = result + " " + getAuthorString(taxon);
1657 }
1658 taxon = null;
1659 }
1660 }
1661 taxa = null;
1662 nvn = null;
1663 return result;
1664 }
1665
1666 /**
1667 * Returns the <code>FullName</code> attribute.
1668 * @param taxon The {@link TaxonBase taxon}.
1669 * @return The <code>FullName</code> attribute.
1670 * @see MethodMapper
1671 */
1672 /*@SuppressWarnings("unused")
1673 private static String getFullName(TaxonBase taxon) {
1674 //TODO extensions?
1675 TaxonNameBase name = taxon.getName();
1676 String result = getFullName(name);
1677 if (isMisappliedName(taxon)){
1678 result = result + " " + getAuthorString(taxon);
1679 }
1680
1681 return result;
1682 }
1683 */
1684
1685 /**
1686 * Returns the nomenclatural reference which is the reference
1687 * including the detail (microreference).
1688 * @param taxonName The {@link TaxonNameBase TaxonName}.
1689 * @return The <code>AuthorString</code> attribute.
1690 * @see MethodMapper
1691 */
1692 @SuppressWarnings("unused")
1693 private static String getNomRefString(TaxonNameBase<?,?> taxonName) {
1694 INomenclaturalReference ref = taxonName.getNomenclaturalReference();
1695 return ref == null ? null : ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());
1696 }
1697
1698
1699 /**
1700 * Returns the <code>NameStatusFk</code> attribute.
1701 * @param taxonName The {@link TaxonNameBase TaxonName}.
1702 * @return The <code>NameStatusFk</code> attribute.
1703 * @see MethodMapper
1704 */
1705 @SuppressWarnings("unused")
1706 private static Integer getNameStatusFk(TaxonNameBase<?,?> taxonName) {
1707 Integer result = null;
1708
1709 NomenclaturalStatus state = getNameStatus(taxonName);
1710 if (state != null) {
1711 result = PesiTransformer.nomStatus2nomStatusFk(state.getType());
1712 }
1713 return result;
1714 }
1715
1716 /**
1717 * Returns the <code>NameStatusCache</code> attribute.
1718 * @param taxonName The {@link TaxonNameBase TaxonName}.
1719 * @return The <code>NameStatusCache</code> attribute.
1720 * @throws UndefinedTransformerMethodException
1721 * @see MethodMapper
1722 */
1723 @SuppressWarnings("unused")
1724 private static String getNameStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1725 String result = null;
1726 NomenclaturalStatus status = getNameStatus(taxonName);
1727 if (status != null) {
1728 result = state.getTransformer().getCacheByNomStatus(status.getType());
1729 }
1730 return result;
1731 }
1732
1733
1734 private static NomenclaturalStatus getNameStatus(TaxonNameBase<?,?> taxonName) {
1735 try {
1736 if (taxonName != null && (taxonName.isInstanceOf(NonViralName.class))) {
1737 NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);
1738 Set<NomenclaturalStatus> states = nonViralName.getStatus();
1739 if (states.size() == 1) {
1740 NomenclaturalStatus status = states.iterator().next();
1741 return status;
1742 } else if (states.size() > 1) {
1743 logger.error("This TaxonName has more than one Nomenclatural Status: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1744 }
1745 }
1746
1747 } catch (Exception e) {
1748 e.printStackTrace();
1749 }
1750 return null;
1751 }
1752 /**
1753 * Returns the <code>TaxonStatusFk</code> attribute.
1754 * @param taxonName The {@link TaxonNameBase TaxonName}.
1755 * @param state The {@link PesiExportState PesiExportState}.
1756 * @return The <code>TaxonStatusFk</code> attribute.
1757 * @see MethodMapper
1758 */
1759 private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {
1760 Integer result = null;
1761
1762 try {
1763 if (isMisappliedName(taxon)) {
1764 Synonym synonym = Synonym.NewInstance(null, null);
1765
1766 // This works as long as only the instance is important to differentiate between TaxonStatus.
1767 result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in Datawarehouse now.
1768 } else {
1769 result = PesiTransformer.taxonBase2statusFk(taxon);
1770 }
1771
1772 } catch (Exception e) {
1773 e.printStackTrace();
1774 }
1775 return result;
1776 }
1777
1778 /**
1779 * Returns the <code>TaxonStatusCache</code> attribute.
1780 * @param taxonName The {@link TaxonNameBase TaxonName}.
1781 * @param state The {@link PesiExportState PesiExportState}.
1782 * @return The <code>TaxonStatusCache</code> attribute.
1783 * @throws UndefinedTransformerMethodException
1784 * @see MethodMapper
1785 */
1786 @SuppressWarnings("unused")
1787 private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) throws UndefinedTransformerMethodException {
1788 return state.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon, state));
1789 }
1790
1791 /**
1792 * Returns the <code>TypeNameFk</code> attribute.
1793 * @param taxonName The {@link TaxonNameBase TaxonName}.
1794 * @param state The {@link PesiExportState PesiExportState}.
1795 * @return The <code>TypeNameFk</code> attribute.
1796 * @see MethodMapper
1797 */
1798 private static Integer getTypeNameFk(TaxonNameBase<?,?> taxonNameBase, PesiExportState state) {
1799 Integer result = null;
1800 if (taxonNameBase != null) {
1801 Set<NameTypeDesignation> nameTypeDesignations = taxonNameBase.getNameTypeDesignations();
1802 if (nameTypeDesignations.size() == 1) {
1803 NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1804 if (nameTypeDesignation != null) {
1805 TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1806 if (typeName != null) {
1807 result = state.getDbId(typeName);
1808 }
1809 }
1810 } else if (nameTypeDesignations.size() > 1) {
1811 logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonNameBase.getUuid() + " (" + taxonNameBase.getTitleCache() + ")");
1812 }
1813 }
1814 return result;
1815 }
1816
1817 /**
1818 * Returns the <code>TypeFullnameCache</code> attribute.
1819 * @param taxonName The {@link TaxonNameBase TaxonName}.
1820 * @return The <code>TypeFullnameCache</code> attribute.
1821 * @see MethodMapper
1822 */
1823 @SuppressWarnings("unused")
1824 private static String getTypeFullnameCache(TaxonNameBase<?,?> taxonName) {
1825 String result = null;
1826
1827 try {
1828 if (taxonName != null) {
1829 Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
1830 if (nameTypeDesignations.size() == 1) {
1831 NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1832 if (nameTypeDesignation != null) {
1833 TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1834 if (typeName != null) {
1835 result = typeName.getTitleCache();
1836 }
1837 }
1838 } else if (nameTypeDesignations.size() > 1) {
1839 logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1840 }
1841 }
1842
1843 } catch (Exception e) {
1844 e.printStackTrace();
1845 }
1846 return result;
1847 }
1848
1849
1850 /**
1851 * Returns the <code>QualityStatusFk</code> attribute.
1852 * @param taxonName The {@link TaxonNameBase TaxonName}.
1853 * @return The <code>QualityStatusFk</code> attribute.
1854 * @see MethodMapper
1855 */
1856 private static Integer getQualityStatusFk(TaxonNameBase taxonName) {
1857 BitSet sources = getSources(taxonName);
1858 return PesiTransformer.getQualityStatusKeyBySource(sources, taxonName);
1859 }
1860
1861
1862 /**
1863 * Returns the <code>QualityStatusCache</code> attribute.
1864 * @param taxonName The {@link TaxonNameBase TaxonName}.
1865 * @return The <code>QualityStatusCache</code> attribute.
1866 * @throws UndefinedTransformerMethodException
1867 * @see MethodMapper
1868 */
1869 @SuppressWarnings("unused")
1870 private static String getQualityStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1871 return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));
1872 }
1873
1874
1875 /**
1876 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1877 * @param taxonName The {@link TaxonNameBase TaxonName}.
1878 * @return The <code>TypeDesignationStatusFk</code> attribute.
1879 * @see MethodMapper
1880 */
1881 @SuppressWarnings("unused")
1882 private static Integer getTypeDesignationStatusFk(TaxonNameBase<?,?> taxonName) {
1883 Integer result = null;
1884
1885 try {
1886 if (taxonName != null) {
1887 Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1888 if (typeDesignations.size() == 1) {
1889 Object obj = typeDesignations.iterator().next().getTypeStatus();
1890 NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1891 result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);
1892 } else if (typeDesignations.size() > 1) {
1893 logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1894 }
1895 }
1896
1897 } catch (Exception e) {
1898 e.printStackTrace();
1899 }
1900 return result;
1901 }
1902
1903 /**
1904 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1905 * @param taxonName The {@link TaxonNameBase TaxonName}.
1906 * @return The <code>TypeDesignationStatusCache</code> attribute.
1907 * @see MethodMapper
1908 */
1909 @SuppressWarnings("unused")
1910 private static String getTypeDesignationStatusCache(TaxonNameBase<?,?> taxonName) {
1911 String result = null;
1912
1913 try {
1914 if (taxonName != null) {
1915 Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1916 if (typeDesignations.size() == 1) {
1917 Object obj = typeDesignations.iterator().next().getTypeStatus();
1918 NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1919 result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);
1920 } else if (typeDesignations.size() > 1) {
1921 logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1922 }
1923 }
1924
1925 } catch (Exception e) {
1926 e.printStackTrace();
1927 }
1928 return result;
1929 }
1930
1931 /**
1932 * Returns the <code>FossilStatusFk</code> attribute.
1933 * @param taxonName The {@link TaxonNameBase TaxonName}.
1934 * @return The <code>FossilStatusFk</code> attribute.
1935 * @see MethodMapper
1936 */
1937 @SuppressWarnings("unused")
1938 private static Integer getFossilStatusFk(IdentifiableEntity<?> identEntity, PesiExportState state) {
1939 Integer result = null;
1940
1941 Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
1942 if (fossilStatuus.size() == 0){
1943 return null;
1944 }else if (fossilStatuus.size() > 1){
1945 logger.warn("More than 1 fossil status given for " + identEntity.getTitleCache() + " " + identEntity.getUuid());
1946 }
1947 String fossilStatus = fossilStatuus.iterator().next();
1948
1949 int statusFk = state.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus);
1950 return statusFk;
1951 }
1952
1953 /**
1954 * Returns the <code>FossilStatusCache</code> attribute.
1955 * @param taxonName The {@link TaxonNameBase TaxonName}.
1956 * @return The <code>FossilStatusCache</code> attribute.
1957 * @see MethodMapper
1958 */
1959 @SuppressWarnings("unused")
1960 private static String getFossilStatusCache(IdentifiableEntity<?> identEntity, PesiExportState state) {
1961 String result = null;
1962 Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
1963 if (fossilStatuus.size() == 0){
1964 return null;
1965 }
1966 for (String strFossilStatus : fossilStatuus){
1967 result = CdmUtils.concat(";", result, strFossilStatus);
1968 }
1969 return result;
1970 }
1971
1972 /**
1973 * Returns the <code>IdInSource</code> attribute.
1974 * @param taxonName The {@link TaxonNameBase TaxonName}.
1975 * @return The <code>IdInSource</code> attribute.
1976 * @see MethodMapper
1977 */
1978 @SuppressWarnings("unused")
1979 private static String getIdInSource(IdentifiableEntity taxonName) {
1980 String result = null;
1981
1982 try {
1983 Set<IdentifiableSource> sources = getPesiSources(taxonName);
1984 if (sources.size() > 1){
1985 logger.warn("There is > 1 Pesi source. This is not yet handled.");
1986 }
1987 if (sources.size() == 0){
1988 logger.warn("There is no Pesi source!" +taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1989 }
1990 for (IdentifiableSource source : sources) {
1991 Reference<?> ref = source.getCitation();
1992 UUID refUuid = ref.getUuid();
1993 String idInSource = source.getIdInSource();
1994 if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
1995 result = idInSource != null ? ("NameId: " + source.getIdInSource()) : null;
1996 }else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
1997 result = idInSource != null ? ("TAX_ID: " + source.getIdInSource()) : null;
1998 }else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
1999 result = idInSource != null ? ("tu_id: " + source.getIdInSource()) : null;
2000 }else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){ //Index Fungorum
2001 result = idInSource != null ? ("if_id: " + source.getIdInSource()) : null;
2002 }else{
2003 if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
2004 }
2005
2006 String sourceIdNameSpace = source.getIdNamespace();
2007 if (sourceIdNameSpace != null) {
2008 if (sourceIdNameSpace.equals(PesiTransformer.STR_NAMESPACE_NOMINAL_TAXON)) {
2009 result = idInSource != null ? ("Nominal Taxon from TAX_ID: " + source.getIdInSource()):null;
2010 } else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_EPITHET_NAMESPACE)) {
2011 result = idInSource != null ? ("Inferred epithet from TAX_ID: " + source.getIdInSource()) : null;
2012 } else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_GENUS_NAMESPACE)) {
2013 result = idInSource != null ? ("Inferred genus from TAX_ID: " + source.getIdInSource()):null;
2014 } else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {
2015 result = idInSource != null ? ("Potential combination from TAX_ID: " + source.getIdInSource()):null;
2016 }
2017 }
2018 if (result == null) {
2019 logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +", sourceIdNameSpace: " + source.getIdNamespace()+")");
2020 }
2021 }
2022 } catch (Exception e) {
2023 e.printStackTrace();
2024 logger.error("An error occurs while creating idInSource..." + taxonName.getUuid() + " (" + taxonName.getTitleCache()+ e.getMessage());
2025 }
2026
2027 if (result == null) {
2028 logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
2029 }
2030 return result;
2031 }
2032
2033 /**
2034 * Returns the idInSource for a given TaxonName only.
2035 * @param taxonName The {@link TaxonNameBase TaxonName}.
2036 * @return The idInSource.
2037 */
2038 private static String getIdInSourceOnly(IdentifiableEntity identEntity) {
2039 String result = null;
2040
2041 // Get the sources first
2042 Set<IdentifiableSource> sources = getPesiSources(identEntity);
2043
2044 // Determine the idInSource
2045 if (sources.size() == 1) {
2046 IdentifiableSource source = sources.iterator().next();
2047 if (source != null) {
2048 result = source.getIdInSource();
2049 }
2050 } else if (sources.size() > 1) {
2051 int count = 1;
2052 result = "";
2053 for (IdentifiableSource source : sources) {
2054 result += source.getIdInSource();
2055 if (count < sources.size()) {
2056 result += "; ";
2057 }
2058 count++;
2059 }
2060
2061 }
2062
2063 return result;
2064 }
2065
2066 /**
2067 * Returns the Sources for a given TaxonName only.
2068 * @param taxonName The {@link TaxonNameBase TaxonName}.
2069 * @return The Sources.
2070 */
2071 private static Set<IdentifiableSource> getPesiSources(IdentifiableEntity identEntity) {
2072 Set<IdentifiableSource> sources = new java.util.HashSet<IdentifiableSource>();
2073
2074 //Taxon Names
2075 if (identEntity.isInstanceOf(TaxonNameBase.class)){
2076 // Sources from TaxonName
2077 TaxonNameBase taxonName = CdmBase.deproxy(identEntity, TaxonNameBase.class);
2078 Set<IdentifiableSource> testSources = identEntity.getSources();
2079 sources = filterPesiSources(identEntity.getSources());
2080
2081 if (sources.size() == 0 && testSources.size()>0){
2082 IdentifiableSource source = testSources.iterator().next();
2083 logger.warn("There are sources, but they are no pesi sources!!!" + source.getIdInSource() + " - " + source.getIdNamespace() + " - "+source.getCitation().generateTitle());
2084 }
2085 if (sources.size() > 1) {
2086 logger.warn("This TaxonName has more than one Source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() + ")");
2087 }
2088
2089 // name has no PESI source, take sources from TaxonBase
2090 if (sources == null || sources.isEmpty()) {
2091 Set<TaxonBase> taxa = taxonName.getTaxonBases();
2092 for (TaxonBase taxonBase: taxa){
2093 sources.addAll(filterPesiSources(taxonBase.getSources()));
2094 }
2095 }
2096
2097 //for TaxonBases
2098 }else if (identEntity.isInstanceOf(TaxonBase.class)){
2099 sources = filterPesiSources(identEntity.getSources());
2100 }
2101
2102 /*TODO: deleted only for testing the inferred synonyms
2103 if (sources == null || sources.isEmpty()) {
2104 logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2105 }else if (sources.size() > 1){
2106 logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2107 }
2108 */
2109 return sources;
2110 }
2111
2112 // return all sources with a PESI reference
2113 private static Set<IdentifiableSource> filterPesiSources(Set<? extends IdentifiableSource> sources) {
2114 Set<IdentifiableSource> result = new HashSet<IdentifiableSource>();
2115 for (IdentifiableSource source : sources){
2116 Reference ref = source.getCitation();
2117 UUID refUuid = ref.getUuid();
2118 if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed) ||
2119 refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)||
2120 refUuid.equals(PesiTransformer.uuidSourceRefErms)||
2121 refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum) ||
2122 refUuid.equals(PesiTransformer.uuidSourceRefAuct)){
2123 result.add(source);
2124 }
2125 }
2126 return result;
2127 }
2128
2129 /**
2130 * Returns the <code>GUID</code> attribute.
2131 * @param taxonName The {@link TaxonNameBase TaxonName}.
2132 * @return The <code>GUID</code> attribute.
2133 * @see MethodMapper
2134 */
2135 private static String getGUID(TaxonBase<?> taxon) {
2136 if (taxon.getLsid() != null ){
2137 return taxon.getLsid().getLsid();
2138 }else if (taxon.hasMarker(PesiTransformer.uuidMarkerGuidIsMissing, true)){
2139 return null;
2140 }else{
2141 return taxon.getUuid().toString();
2142 }
2143 }
2144
2145
2146
2147
2148 /**
2149 * Returns the <code>DerivedFromGuid</code> attribute.
2150 * @param taxonName The {@link TaxonNameBase TaxonName}.
2151 * @return The <code>DerivedFromGuid</code> attribute.
2152 * @see MethodMapper
2153 */
2154 @SuppressWarnings("unused")
2155 private static String getDerivedFromGuid(TaxonBase<?> taxon) {
2156 String result = null;
2157 try {
2158 // The same as GUID for now
2159 result = getGUID(taxon);
2160 } catch (Exception e) {
2161 e.printStackTrace();
2162 }
2163 return result;
2164 }
2165
2166 /**
2167 * Returns the <code>CacheCitation</code> attribute.
2168 * @param taxonName The {@link TaxonNameBase TaxonName}.
2169 * @return The CacheCitation.
2170 * @see MethodMapper
2171 */
2172 @SuppressWarnings("unused")
2173 private static String getCacheCitation(TaxonBase taxon) {
2174 // !!! See also doPhaseUpdates
2175
2176 TaxonNameBase<?,?> taxonName = taxon.getName();
2177 String result = "";
2178 //TODO implement anew for taxa
2179 try {
2180 BitSet sources = getSources(taxonName);
2181 if (sources.isEmpty()) {
2182 // logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2183 } else if (sources.get(PesiTransformer.SOURCE_ERMS)) {
2184 // 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...
2185 // So the following code is some kind of harmless assumption.
2186 Set<Extension> extensions = taxonName.getExtensions();
2187 for (Extension extension : extensions) {
2188 if (extension.getType().equals(cacheCitationExtensionType)) {
2189 result = extension.getValue();
2190 }
2191 }
2192 } else {
2193 String expertName = getExpertName(taxon);
2194 String webShowName = getWebShowName(taxonName);
2195
2196 // idInSource only
2197 String idInSource = getIdInSourceOnly(taxonName);
2198
2199 // build the cacheCitation
2200 if (expertName != null) {
2201 result += expertName + ". ";
2202 } else {
2203 if (logger.isDebugEnabled()){logger.debug("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");}
2204 }
2205 if (webShowName != null) {
2206 result += webShowName + ". ";
2207 } else {
2208 logger.warn("WebShowName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2209 }
2210
2211 if (getOriginalDB(taxonName).equals("FaEu")) {
2212 result += "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
2213 } else if (getOriginalDB(taxonName).equals("EM")) {
2214 result += "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
2215 }
2216
2217 if (idInSource != null) {
2218 result += idInSource;
2219 } else {
2220 logger.warn("IdInSource could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2221 }
2222 }
2223 } catch (Exception e) {
2224 e.printStackTrace();
2225 }
2226
2227 if (StringUtils.isBlank(result)) {
2228 return null;
2229 } else {
2230 return result;
2231 }
2232 }
2233
2234 /**
2235 * Returns the <code>OriginalDB</code> attribute.
2236 * @param taxonName The {@link TaxonNameBase TaxonName}.
2237 * @return The <code>OriginalDB</code> attribute.
2238 * @see MethodMapper
2239 */
2240 private static String getOriginalDB(IdentifiableEntity identEntity) {
2241 // Sources from TaxonName
2242 BitSet sources = getSources(identEntity);
2243 return PesiTransformer.getOriginalDbBySources(sources);
2244 }
2245
2246 /**
2247 * Returns the <code>LastAction</code> attribute.
2248 * @param taxonName The {@link TaxonNameBase TaxonName}.
2249 * @return The <code>LastAction</code> attribute.
2250 * @see MethodMapper
2251 */
2252 @SuppressWarnings("unused")
2253 private static String getLastAction(IdentifiableEntity<?> identEntity) {
2254 String result = null;
2255 try {
2256 Set<Extension> extensions = identEntity.getExtensions();
2257 for (Extension extension : extensions) {
2258 if (extension.getType().equals(lastActionExtensionType)) {
2259 result = extension.getValue();
2260 }
2261 }
2262 } catch (Exception e) {
2263 e.printStackTrace();
2264 }
2265 return result;
2266 }
2267
2268 /**
2269 * Returns the <code>LastActionDate</code> attribute.
2270 * @param taxonName The {@link TaxonNameBase TaxonName}.
2271 * @return The <code>LastActionDate</code> attribute.
2272 * @see MethodMapper
2273 */
2274 @SuppressWarnings({ "unused" })
2275 private static DateTime getLastActionDate(IdentifiableEntity identEntity) {
2276 DateTime result = null;
2277 try {
2278 Set<Extension> extensions = identEntity.getExtensions();
2279 for (Extension extension : extensions) {
2280 if (extension.getType().equals(lastActionDateExtensionType)) {
2281 String dateTime = extension.getValue();
2282 if (dateTime != null) {
2283 DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S");
2284 result = formatter.parseDateTime(dateTime);
2285 }
2286 }
2287 }
2288 } catch (Exception e) {
2289 e.printStackTrace();
2290 }
2291 return result;
2292 }
2293
2294 /**
2295 * Returns the <code>ExpertName</code> attribute.
2296 * @param taxonName The {@link TaxonNameBase TaxonName}.
2297 * @return The <code>ExpertName</code> attribute.
2298 * @see MethodMapper
2299 */
2300 @SuppressWarnings("unused")
2301 private static String getExpertName(TaxonBase<?> taxonName) {
2302 String result = null;
2303 try {
2304 Set<Extension> extensions = taxonName.getExtensions();
2305 for (Extension extension : extensions) {
2306 if (extension.getType().equals(expertNameExtensionType)) {
2307 result = extension.getValue();
2308 }
2309 }
2310 } catch (Exception e) {
2311 e.printStackTrace();
2312 }
2313 return result;
2314 }
2315
2316 /**
2317 * Returns the <code>ExpertFk</code> attribute.
2318 * @param taxonName The {@link TaxonNameBase TaxonName}.
2319 * @param state The {@link PesiExportState PesiExportState}.
2320 * @return The <code>ExpertFk</code> attribute.
2321 * @see MethodMapper
2322 */
2323 private static Integer getExpertFk(Reference<?> reference, PesiExportState state) {
2324 Integer result = state.getDbId(reference);
2325 return result;
2326 }
2327
2328 /**
2329 * Returns the <code>SpeciesExpertName</code> attribute.
2330 * @param taxonName The {@link TaxonNameBase TaxonName}.
2331 * @return The <code>SpeciesExpertName</code> attribute.
2332 * @see MethodMapper
2333 */
2334 @SuppressWarnings("unused")
2335 private static String getSpeciesExpertName(TaxonBase<?> taxonName) {
2336 String result = null;
2337 try {
2338 Set<Extension> extensions = taxonName.getExtensions();
2339 for (Extension extension : extensions) {
2340 if (extension.getType().equals(speciesExpertNameExtensionType)) {
2341 result = extension.getValue();
2342 }
2343 }
2344 } catch (Exception e) {
2345 e.printStackTrace();
2346 }
2347 return result;
2348 }
2349
2350 /**
2351 * Returns the <code>SpeciesExpertFk</code> attribute.
2352 * @param reference The {@link Reference Reference}.
2353 * @param state The {@link PesiExportState PesiExportState}.
2354 * @return The <code>SpeciesExpertFk</code> attribute.
2355 * @see MethodMapper
2356 */
2357 private static Integer getSpeciesExpertFk(Reference<?> reference, PesiExportState state) {
2358 Integer result = state.getDbId(reference);
2359 return result;
2360 }
2361
2362
2363 /**
2364 * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
2365 * Identifiable Entity as a BitSet
2366 * @param identEntity
2367 * @return
2368 */
2369 private static BitSet getSources(IdentifiableEntity<?> identEntity){
2370 BitSet bitSet = new BitSet();
2371 Set<IdentifiableSource> sources = getPesiSources(identEntity);
2372 for (IdentifiableSource source : sources) {
2373 Reference<?> ref = source.getCitation();
2374 UUID refUuid = ref.getUuid();
2375 if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
2376 bitSet.set(PesiTransformer.SOURCE_EM);
2377 }else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
2378 bitSet.set(PesiTransformer.SOURCE_FE);
2379 }else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
2380 bitSet.set(PesiTransformer.SOURCE_ERMS);
2381 }else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){
2382 bitSet.set(PesiTransformer.SOURCE_IF);
2383 }else{
2384 if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
2385 }
2386 }
2387 return bitSet;
2388
2389 }
2390
2391 protected static NonViralNameDefaultCacheStrategy getCacheStrategy(TaxonNameBase<?, ?> taxonName) {
2392 taxonName = CdmBase.deproxy(taxonName, TaxonNameBase.class);
2393 NonViralNameDefaultCacheStrategy<?> cacheStrategy;
2394 if (taxonName.isInstanceOf(ZoologicalName.class)){
2395 cacheStrategy = zooNameStrategy;
2396 }else if (taxonName.isInstanceOf(BotanicalName.class)) {
2397 cacheStrategy = botanicalNameStrategy;
2398 }else if (taxonName.getClass().equals(NonViralName.class)) {
2399 cacheStrategy = nonViralNameStrategy;
2400 }else if (taxonName.getClass().equals(BacterialName.class)) {
2401 cacheStrategy = bacterialNameStrategy;
2402 }else{
2403 logger.error("Unhandled taxon name type. Can't define strategy class");
2404 cacheStrategy = botanicalNameStrategy;
2405 }
2406 return cacheStrategy;
2407 }
2408
2409 /**
2410 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
2411 * @param relationship The {@link RelationshipBase Relationship}.
2412 * @param state The {@link PesiExportState PesiExportState}.
2413 * @return The <code>TaxonFk1</code> attribute.
2414 * @see MethodMapper
2415 */
2416 private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
2417
2418 return getObjectFk(relationship, state, true);
2419 }
2420
2421 /**
2422 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
2423 * @param relationship The {@link RelationshipBase Relationship}.
2424 * @param state The {@link PesiExportState PesiExportState}.
2425 * @return The <code>TaxonFk2</code> attribute.
2426 * @see MethodMapper
2427 */
2428 private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
2429 return getObjectFk(relationship, state, false);
2430 }
2431
2432 /**
2433 * Returns the database key of an object in the given relationship.
2434 * @param relationship {@link RelationshipBase RelationshipBase}.
2435 * @param state {@link PesiExportState PesiExportState}.
2436 * @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.
2437 * @return The database key of an object in the given relationship.
2438 */
2439 private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
2440 TaxonBase<?> taxonBase = null;
2441 if (relationship.isInstanceOf(TaxonRelationship.class)) {
2442 TaxonRelationship tr = (TaxonRelationship)relationship;
2443 taxonBase = (isFrom) ? tr.getFromTaxon(): tr.getToTaxon();
2444 } else if (relationship.isInstanceOf(SynonymRelationship.class)) {
2445 SynonymRelationship sr = (SynonymRelationship)relationship;
2446 taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
2447 } else if (relationship.isInstanceOf(NameRelationship.class) || relationship.isInstanceOf(HybridRelationship.class)) {
2448 if (isFrom){
2449 return state.getDbId(state.getCurrentFromObject());
2450 }else{
2451 return state.getDbId(state.getCurrentToObject());
2452 }
2453 }
2454 if (taxonBase != null) {
2455 if (! isPesiTaxon(taxonBase)){
2456 logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " + relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
2457 return null;
2458 }else{
2459 return state.getDbId(taxonBase);
2460 }
2461
2462 }
2463 logger.warn("No taxon found in state for relationship: " + relationship.toString());
2464 return null;
2465 }
2466
2467 /**
2468 * Returns the <code>RelQualifierCache</code> attribute.
2469 * @param relationship The {@link RelationshipBase Relationship}.
2470 * @return The <code>RelQualifierCache</code> attribute.
2471 * @see MethodMapper
2472 */
2473 @SuppressWarnings("unused")
2474 private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
2475 String result = null;
2476 NomenclaturalCode code = null;
2477 if (relationship.isInstanceOf(TaxonRelationship.class)){
2478 code = CdmBase.deproxy(relationship, TaxonRelationship.class).getToTaxon().getName().getNomenclaturalCode();
2479 }else if (relationship.isInstanceOf(SynonymRelationship.class)){
2480 code = CdmBase.deproxy(relationship, SynonymRelationship.class).getAcceptedTaxon().getName().getNomenclaturalCode();
2481 }else if (relationship.isInstanceOf(NameRelationship.class)){
2482 code = CdmBase.deproxy(relationship, NameRelationship.class).getFromName().getNomenclaturalCode();
2483 }else if (relationship.isInstanceOf(HybridRelationship.class)){
2484 code = CdmBase.deproxy(relationship, HybridRelationship.class).getParentName().getNomenclaturalCode();
2485 }
2486 if (code != null) {
2487 result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
2488 } else {
2489 logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
2490 }
2491 return result;
2492 }
2493
2494 /**
2495 * Returns the <code>RelTaxonQualifierFk</code> attribute.
2496 * @param relationship The {@link RelationshipBase Relationship}.
2497 * @return The <code>RelTaxonQualifierFk</code> attribute.
2498 * @see MethodMapper
2499 */
2500 @SuppressWarnings("unused")
2501 private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
2502 return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
2503 }
2504 /**
2505 * Returns the <code>Notes</code> attribute.
2506 * @param relationship The {@link RelationshipBase Relationship}.
2507 * @return The <code>Notes</code> attribute.
2508 * @see MethodMapper
2509 */
2510 @SuppressWarnings("unused")
2511 private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
2512 // TODO
2513 return null;
2514 }
2515
2516
2517 /**
2518 * Returns the CDM to PESI specific export mappings.
2519 * @return The {@link PesiExportMapping PesiExportMapping}.
2520 */
2521 private PesiExportMapping getMapping() {
2522 PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2523
2524 mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2525 mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2526 mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2527 mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
2528
2529 mapping.addMapper(MethodMapper.NewInstance("GUID", this));
2530
2531 mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));
2532 mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));
2533 mapping.addMapper(MethodMapper.NewInstance("AuthorString", this)); //For Taxon because Misallied Names are handled differently
2534 mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));
2535
2536 // DisplayName
2537 mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));
2538
2539 // FossilStatus (Fk, Cache)
2540 mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, IdentifiableEntity.class, PesiExportState.class));
2541 mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, IdentifiableEntity.class, PesiExportState.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2542
2543 //handled by name mapping
2544 mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2545 mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2546
2547 //experts
2548 ExtensionType extensionTypeSpeciesExpertName = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
2549 mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));
2550 ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
2551 mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));
2552
2553 // mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class)); //by AM, doesn't work, FK exception
2554 mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2555
2556 addNameMappers(mapping);
2557
2558 return mapping;
2559 }
2560
2561 /**
2562 * Returns the CDM to PESI specific export mappings.
2563 * @param state
2564 * @return The {@link PesiExportMapping PesiExportMapping}.
2565 * @throws UndefinedTransformerMethodException
2566 */
2567 private PesiExportMapping getPureNameMapping(PesiExportState state) throws UndefinedTransformerMethodException {
2568 PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2569
2570 mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2571
2572 // mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2573
2574 mapping.addMapper(MethodMapper.NewInstance("KingdomFk", this, TaxonNameBase.class));
2575 mapping.addMapper(MethodMapper.NewInstance("RankFk", this, TaxonNameBase.class));
2576 mapping.addMapper(MethodMapper.NewInstance("RankCache", this, TaxonNameBase.class, PesiExportState.class));
2577 mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER , PesiTransformer.T_STATUS_UNACCEPTED));
2578 mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR , state.getTransformer().getTaxonStatusCacheByKey( PesiTransformer.T_STATUS_UNACCEPTED)));
2579 mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
2580 mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));
2581
2582 // DisplayName
2583 mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));
2584
2585 mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2586 mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2587
2588 addNameMappers(mapping);
2589 //TODO add author mapper, TypeNameFk
2590
2591 return mapping;
2592 }
2593
2594 private void addNameMappers(PesiExportMapping mapping) {
2595 mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2596 mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2597 mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));
2598 mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2599
2600 // mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName")); //does not work as we need other cache strategy
2601 mapping.addMapper(MethodMapper.NewInstance("WebSearchName", this, TaxonNameBase.class));
2602
2603 // mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName")); //does not work as we need other cache strategy
2604 mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonNameBase.class));
2605
2606
2607 mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonNameBase.class));
2608
2609 mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));
2610 mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2611 mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonNameBase.class));
2612 //TODO TypeNameFk
2613
2614 //quality status
2615 mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonNameBase.class));
2616 mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2617
2618 mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));
2619 mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );
2620
2621 //mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2622
2623 }
2624
2625 private PesiExportMapping getSynRelMapping() {
2626 PesiExportMapping mapping = new PesiExportMapping(dbTableNameSynRel);
2627
2628 mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase.class, PesiExportState.class));
2629 mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase.class, PesiExportState.class));
2630 mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this, RelationshipBase.class));
2631 mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
2632 mapping.addMapper(MethodMapper.NewInstance("Notes", this, RelationshipBase.class));
2633
2634 return mapping;
2635 }
2636
2637 private PesiExportMapping getAdditionalSourceMapping(PesiExportState state) throws UndefinedTransformerMethodException{
2638 PesiExportMapping mapping = new PesiExportMapping(dbTableAdditionalSourceRel);
2639
2640 mapping.addMapper(IdMapper.NewInstance("TaxonFk"));
2641 mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2642
2643 mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceFk"));
2644 mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE));
2645
2646 //we have only nomenclatural references here
2647 mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER , PesiTransformer.NOMENCLATURAL_REFERENCE));
2648 mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, state.getTransformer().getSourceUseCacheByKey( PesiTransformer.NOMENCLATURAL_REFERENCE)));
2649
2650 mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "SourceDetail"));
2651
2652 return mapping;
2653 }
2654
2655 }