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