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