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