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