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