Project

General

Profile

Download (103 KB) Statistics
| Branch: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2009 EDIT
4
* European Distributed Institute of Taxonomy 
5
* http://www.e-taxonomy.eu
6
* 
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.cdm.io.pesi.out;
11

    
12
import java.sql.Connection;
13
import java.sql.PreparedStatement;
14
import java.sql.ResultSet;
15
import java.sql.SQLException;
16
import java.sql.Types;
17
import java.util.ArrayList;
18
import java.util.BitSet;
19
import java.util.HashMap;
20
import java.util.HashSet;
21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Set;
24
import java.util.UUID;
25

    
26
import org.apache.commons.lang.StringUtils;
27
import org.apache.log4j.Logger;
28
import org.joda.time.DateTime;
29
import org.joda.time.format.DateTimeFormat;
30
import org.joda.time.format.DateTimeFormatter;
31
import org.springframework.stereotype.Component;
32
import org.springframework.transaction.TransactionStatus;
33

    
34
import eu.etaxonomy.cdm.api.service.TaxonServiceImpl;
35
import eu.etaxonomy.cdm.common.CdmUtils;
36
import eu.etaxonomy.cdm.io.common.Source;
37
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
38
import eu.etaxonomy.cdm.io.common.mapping.out.DbConstantMapper;
39
import eu.etaxonomy.cdm.io.common.mapping.out.DbExtensionMapper;
40
import eu.etaxonomy.cdm.io.common.mapping.out.DbLastActionMapper;
41
import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
42
import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
43
import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
44
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
45
import eu.etaxonomy.cdm.io.common.mapping.out.ObjectChangeMapper;
46
import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;
47
import eu.etaxonomy.cdm.io.profiler.ProfilerController;
48
import eu.etaxonomy.cdm.model.common.Annotation;
49
import eu.etaxonomy.cdm.model.common.AnnotationType;
50
import eu.etaxonomy.cdm.model.common.CdmBase;
51
import eu.etaxonomy.cdm.model.common.Extension;
52
import eu.etaxonomy.cdm.model.common.ExtensionType;
53
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
54
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
55
import eu.etaxonomy.cdm.model.common.Language;
56
import eu.etaxonomy.cdm.model.common.Marker;
57
import eu.etaxonomy.cdm.model.common.MarkerType;
58
import eu.etaxonomy.cdm.model.common.RelationshipBase;
59
import eu.etaxonomy.cdm.model.name.BacterialName;
60
import eu.etaxonomy.cdm.model.name.BotanicalName;
61
import eu.etaxonomy.cdm.model.name.HybridRelationship;
62
import eu.etaxonomy.cdm.model.name.NameRelationship;
63
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
64
import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
65
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
66
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
67
import eu.etaxonomy.cdm.model.name.NonViralName;
68
import eu.etaxonomy.cdm.model.name.Rank;
69
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
70
import eu.etaxonomy.cdm.model.name.ZoologicalName;
71
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
72
import eu.etaxonomy.cdm.model.reference.Reference;
73
import eu.etaxonomy.cdm.model.taxon.Classification;
74
import eu.etaxonomy.cdm.model.taxon.Synonym;
75
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
76
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
77
import eu.etaxonomy.cdm.model.taxon.Taxon;
78
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
79
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
80
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
81
import eu.etaxonomy.cdm.strategy.cache.HTMLTagRules;
82
import eu.etaxonomy.cdm.strategy.cache.TagEnum;
83
import eu.etaxonomy.cdm.strategy.cache.name.BacterialNameDefaultCacheStrategy;
84
import eu.etaxonomy.cdm.strategy.cache.name.BotanicNameDefaultCacheStrategy;
85
import eu.etaxonomy.cdm.strategy.cache.name.INonViralNameCacheStrategy;
86
import eu.etaxonomy.cdm.strategy.cache.name.NonViralNameDefaultCacheStrategy;
87
import eu.etaxonomy.cdm.strategy.cache.name.ZooNameNoMarkerCacheStrategy;
88

    
89
/**
90
 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
91
 * Inserts into DataWarehouse database table <code>Taxon</code>.
92
 * It is divided into four phases:<p><ul>
93
 * <li>Phase 1:	Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.
94
 * <li>Phase 2:	Export of additional data: ParenTaxonFk and TreeIndex.
95
 * <li>Phase 3:	Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
96
 * <li>Phase 4:	Export of Inferred Synonyms.</ul>
97
 * @author e.-m.lee
98
 * @date 23.02.2010
99
 *
100
 */
101
@Component
102
public class PesiTaxonExport extends PesiExportBase {
103
	private static final Logger logger = Logger.getLogger(PesiTaxonExport.class);
104
	private static final Class<? extends CdmBase> standardMethodParameter = TaxonBase.class;
105

    
106
	private static int modCount = 1000;
107
	private static final String dbTableName = "Taxon";
108
	private static final String dbTableNameSynRel = "RelTaxon";
109
	private static final String dbTableAdditionalSourceRel = "AdditionalTaxonSource";
110
	private static final String pluralString = "Taxa";
111
	private static final String parentPluralString = "Taxa";
112
	private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt;
113
	private PreparedStatement parentTaxonFkStmt;
114
	private PreparedStatement rankTypeExpertsUpdateStmt;
115
	private PreparedStatement rankUpdateStmt;
116
	private NomenclaturalCode nomenclaturalCode;
117
	private Integer kingdomFk;
118
	private HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();
119
	private List<Rank> rankList = new ArrayList<Rank>();
120
	private static final UUID uuidTreeIndex = UUID.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");
121
	private AnnotationType treeIndexAnnotationType;
122
	private static ExtensionType lastActionExtensionType;
123
	private static ExtensionType lastActionDateExtensionType;
124
	private static ExtensionType expertNameExtensionType;
125
	private static ExtensionType speciesExpertNameExtensionType;
126
	private static ExtensionType cacheCitationExtensionType;
127
	public static NonViralNameDefaultCacheStrategy<?> zooNameStrategy = ZooNameNoMarkerCacheStrategy.NewInstance();
128
	public static NonViralNameDefaultCacheStrategy<?> botanicalNameStrategy = BotanicNameDefaultCacheStrategy.NewInstance();
129
	public static NonViralNameDefaultCacheStrategy<?> nonViralNameStrategy = NonViralNameDefaultCacheStrategy.NewInstance();
130
	public static NonViralNameDefaultCacheStrategy<?> bacterialNameStrategy = BacterialNameDefaultCacheStrategy.NewInstance();
131
	private static int currentTaxonId;
132
	
133
	
134
	/**
135
	 * @return the treeIndexAnnotationType
136
	 */
137
	protected AnnotationType getTreeIndexAnnotationType() {
138
		return treeIndexAnnotationType;
139
	}
140

    
141
	/**
142
	 * @param treeIndexAnnotationType the treeIndexAnnotationType to set
143
	 */
144
	protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType) {
145
		this.treeIndexAnnotationType = treeIndexAnnotationType;
146
	}
147

    
148
	enum NamePosition {
149
		beginning,
150
		end,
151
		between,
152
		alone,
153
		nowhere
154
	}
155

    
156
	public PesiTaxonExport() {
157
		super();
158
	}
159

    
160
	/* (non-Javadoc)
161
	 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
162
	 */
163
	@Override
164
	public Class<? extends CdmBase> getStandardMethodParameter() {
165
		return standardMethodParameter;
166
	}
167

    
168
	/* (non-Javadoc)
169
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
170
	 */
171
	@Override
172
	protected boolean doCheck(PesiExportState state) {
173
		boolean result = true;
174
		return result;
175
	}
176
	
177
	
178
	/* (non-Javadoc)
179
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
180
	 */
181
	@Override
182
	protected void doInvoke(PesiExportState state) {
183
		try {
184
			logger.info("*** Started Making " + pluralString + " ...");
185

    
186
			initPreparedStatements(state);
187
			
188
			// Stores whether this invoke was successful or not.
189
			boolean success = true;
190
	
191
			// PESI: Clear the database table Taxon.
192
//			doDelete(state);
193
			
194
			// Get specific mappings: (CDM) Taxon -> (PESI) Taxon
195
			PesiExportMapping mapping = getMapping();
196
			PesiExportMapping synonymRelMapping = getSynRelMapping();
197
			PesiExportMapping additionalSourceMapping = getAdditionalSourceMapping(state); 
198
			
199
			// Initialize the db mapper
200
			mapping.initialize(state);
201
			synonymRelMapping.initialize(state);
202
			additionalSourceMapping.initialize(state);
203
			
204
			// Find extensionTypes
205
			lastActionExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionUuid);
206
			lastActionDateExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionDateUuid);
207
			expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
208
			speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
209
			cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.cacheCitationUuid);
210
			
211
			//Export Taxa..
212
			success &= doPhase01(state, mapping, additionalSourceMapping);
213

    
214
			//"PHASE 1b: Handle names without taxa ...
215
			success &= doNames(state, additionalSourceMapping);
216

    
217
			
218
			// 2nd Round: Add ParentTaxonFk to each taxon
219
			success &= doPhase02(state);
220
			
221
			//PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
222
			success &= doPhase03(state);
223
			
224
			// 4nd Round: Add TreeIndex to each taxon
225
			success &= doPhase04(state);
226
						
227
			
228
			//"PHASE 4: Creating Inferred Synonyms...
229
			success &= doPhase05(state, mapping, synonymRelMapping);
230
			
231
			logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
232

    
233
			if (!success){
234
				state.setUnsuccessfull();
235
			}
236
			return;
237
		} catch (Exception e) {
238
			e.printStackTrace();
239
			logger.error(e.getMessage());
240
			state.setUnsuccessfull();
241
		}
242
	}
243

    
244
	
245
	private void initPreparedStatements(PesiExportState state) throws SQLException {
246
		initTreeIndexStatement(state);
247
		initRankExpertsUpdateStmt(state);
248
		initRankUpdateStatement(state);
249
		
250
		initParentFkStatement(state);
251
	}
252

    
253
	// Prepare TreeIndex-And-KingdomFk-Statement
254
	private void initTreeIndexStatement(PesiExportState state) throws SQLException {
255
		Connection connection = state.getConfig().getDestination().getConnection();
256
		String parentTaxonFk_TreeIndex_KingdomFkSql = "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?"; 
257
		parentTaxonFk_TreeIndex_KingdomFkStmt = connection.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql);
258
	}
259

    
260
	// Prepare TreeIndex-And-KingdomFk-Statement
261
	private void initParentFkStatement(PesiExportState state) throws SQLException {
262
		Connection connection = state.getConfig().getDestination().getConnection();
263
		String parentTaxonFkSql = "UPDATE Taxon SET ParentTaxonFk = ? WHERE TaxonId = ?"; 
264
		parentTaxonFkStmt = connection.prepareStatement(parentTaxonFkSql);
265
	}
266
	
267
	private void initRankUpdateStatement(PesiExportState state) throws SQLException {
268
		Connection connection = state.getConfig().getDestination().getConnection();
269
		String rankSql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
270
		rankUpdateStmt = connection.prepareStatement(rankSql);
271
	}
272

    
273
	private void initRankExpertsUpdateStmt(PesiExportState state) throws SQLException {
274
//		String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
275
//				"ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
276
		//TODO handle experts GUIDs
277
		Connection connection = state.getConfig().getDestination().getConnection();
278
		
279
		String sql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
280
				" WHERE TaxonId = ?";
281
		rankTypeExpertsUpdateStmt = connection.prepareStatement(sql);
282
	}
283

    
284
	private boolean doPhase01(PesiExportState state, PesiExportMapping mapping, PesiExportMapping additionalSourceMapping) throws SQLException {
285
		int count = 0;
286
		int pastCount = 0;
287
		List<TaxonBase> list;
288
		boolean success = true;
289
		// Get the limit for objects to save within a single transaction.
290
		int limit = state.getConfig().getLimitSave();
291

    
292
		
293
		logger.info("PHASE 1: Export Taxa...limit is " + limit);
294
		// Start transaction
295
		TransactionStatus txStatus = startTransaction(true);
296
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
297
		
298
		
299
		
300
		int partitionCount = 0;
301

    
302
		logger.info("Taking snapshot at the beginning of phase 1 of taxonExport");
303
		ProfilerController.memorySnapshot();
304
		while ((list = getNextTaxonPartition(null, limit, partitionCount++, null)) != null   ) {
305
			
306
			logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
307
			for (TaxonBase<?> taxon : list) {
308
				doCount(count++, modCount, pluralString);
309
				TaxonNameBase<?,?> taxonName = taxon.getName();
310
				NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
311
								
312
				if (! nvn.isProtectedTitleCache()){
313
					nvn.setTitleCache(null, false);	
314
				}
315
				if (! nvn.isProtectedNameCache()){
316
					nvn.setNameCache(null, false);	
317
				}
318
				if (! nvn.isProtectedFullTitleCache()){
319
					nvn.setFullTitleCache(null, false);	
320
				}
321
				if (! nvn.isProtectedAuthorshipCache()){
322
					nvn.setAuthorshipCache(null, false);	
323
				}
324
				
325
				//core mapping
326
				success &= mapping.invoke(taxon);
327
				//additional source
328
				if (nvn.getNomenclaturalReference() != null || StringUtils.isNotBlank(nvn.getNomenclaturalMicroReference() )){
329
					additionalSourceMapping.invoke(taxon);
330
				}
331
				
332
				validatePhaseOne(taxon, nvn);
333
				taxon = null;
334
				nvn = null;
335
				taxonName = null;
336

    
337
				
338
				
339
			}
340
			
341

    
342
			// Commit transaction
343
			commitTransaction(txStatus);
344
			logger.debug("Committed transaction.");
345
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
346
			pastCount = count;
347
			/*logger.warn("Taking snapshot at the end of the loop of phase 1 of taxonExport");
348
			ProfilerController.memorySnapshot();
349
			*/
350
			// Start transaction
351
			txStatus = startTransaction(true);
352
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
353
			
354
		}
355
		if (list == null ) {
356
			logger.info("No " + pluralString + " left to fetch.");
357
		}
358
		
359
		
360
		
361
		// Commit transaction
362
		commitTransaction(txStatus);
363
		txStatus = null;
364
		logger.debug("Committed transaction.");
365
		list = null;
366
		if (logger.isDebugEnabled()){
367
			logger.debug("Taking snapshot at the end of phase 1 of taxonExport");
368
			ProfilerController.memorySnapshot();
369
		}
370
		return success;
371
	}
372

    
373

    
374
	private void validatePhaseOne(TaxonBase<?> taxon, NonViralName taxonName) {
375
		// Check whether some rules are violated
376
		nomenclaturalCode = taxonName.getNomenclaturalCode();
377
		String genusOrUninomial = taxonName.getGenusOrUninomial();
378
		String specificEpithet = taxonName.getSpecificEpithet();
379
		String infraSpecificEpithet = taxonName.getInfraSpecificEpithet();
380
		String infraGenericEpithet = taxonName.getInfraGenericEpithet();
381
		Integer rank = getRankFk(taxonName, nomenclaturalCode);
382
		
383
		if (rank == null) {
384
			logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
385
		} else {
386
			
387
			// Check whether infraGenericEpithet is set correctly
388
			// 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
389
			// 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
390
			
391
			int ancestorLevel = 0;
392
			if (taxonName.getRank().equals(Rank.SUBSPECIES())) {
393
				// The accepted taxon two rank levels above should be of rank subgenus
394
				ancestorLevel  = 2;
395
			}
396
			if (taxonName.getRank().equals(Rank.SPECIES())) {
397
				// The accepted taxon one rank level above should be of rank subgenus
398
				ancestorLevel = 1;
399
			}
400
			if (ancestorLevel > 0) {
401
				if (validateAncestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {
402
					// The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
403
					if (infraGenericEpithet == null) {
404
						logger.warn("InfraGenericEpithet does not exist even though it should for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
405
						// maybe the taxon could be named here
406
					}
407
				}
408
			}
409
			
410
			if (infraGenericEpithet == null && rank.intValue() == 190) {
411
				logger.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
412
			}
413
			if (specificEpithet != null && rank.intValue() < 216) {
414
				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() + ")");
415
			}
416
			if (infraSpecificEpithet != null && rank.intValue() < 225) {
417
				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() + ")"; 
418
				if (StringUtils.isNotBlank(infraSpecificEpithet)){
419
					logger.warn(message);
420
				}else{
421
					logger.warn(message);
422
				}
423
			}
424
		}
425
		if (infraSpecificEpithet != null && specificEpithet == null) {
426
			logger.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: "  + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
427
		}
428
		if (genusOrUninomial == null) {
429
			logger.warn("GenusOrUninomial was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
430
		}
431
	}
432

    
433
	
434
	
435
	/**
436
	 * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists
437
	 * @param state
438
	 * @return
439
	 */
440
	private boolean doPhase02(PesiExportState state) {
441
		int count = 0;
442
		int pastCount = 0;
443
		boolean success = true;
444
		if (! state.getConfig().isDoParentAndBiota()){
445
			logger.info ("Ignore PHASE 2: Make ParentFk and Biota...");
446
			return success;
447
		}
448
		
449
		List<Taxon> list;
450
		
451
		// Get the limit for objects to save within a single transaction.
452
		int limit = state.getConfig().getLimitSave();
453
		
454
		insertBiota(state);
455
		
456
		logger.info("PHASE 2: Make ParentFk and Biota ... limit is " + limit);
457
		// Start transaction
458
		TransactionStatus txStatus = startTransaction(true);
459
		int partitionCount = 0;
460

    
461
//		ProfilerController.memorySnapshot();
462
		while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, null)) != null   ) {
463
			
464
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
465
			for (Taxon taxon : list) {
466
				for (TaxonNode node : taxon.getTaxonNodes()){
467
					doCount(count++, modCount, pluralString);
468
					TaxonNode parentNode = node.getParent();
469
					if (parentNode != null){
470
						int childId = state.getDbId( taxon); 
471
						int parentId = state.getDbId(parentNode.getTaxon());
472
						success &= invokeParentTaxonFk(parentId, childId);
473
					}
474
				}
475
				
476
			}
477
			
478
			// Commit transaction
479
			commitTransaction(txStatus);
480
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
481
			pastCount = count;
482
			// Start transaction
483
			txStatus = startTransaction(true);
484
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
485
			
486
		}
487
		if (list == null ) {
488
			logger.info("No " + pluralString + " left to fetch.");
489
		}
490
		
491
		// Commit transaction
492
		commitTransaction(txStatus);
493
		
494
		return success;
495
		
496
	}
497

    
498
	/**
499
	 * Inserts the Biota Taxon if not yet exists.
500
	 * @param state
501
	 * @throws SQLException
502
	 */
503
	private void insertBiota(PesiExportState state) {
504
		try {
505
			ResultSet rs = state.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");
506
			if (rs.next() == false){
507
				int biotaId = state.getConfig().getNameIdStart() -1 ;
508
				String sqlInsertBiota = "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +
509
									       " VALUES (" + biotaId + ",    0,    0,   'Superdomain',   'Biota',          'Biota',  '<i>Biota</i>',   'Biota', '<i>Biota</i>',  1 ,      'accepted')";
510
				state.getConfig().getDestination().update(sqlInsertBiota);
511
			}
512
		} catch (SQLException e) {
513
			logger.warn ("Biota could not be requested or inserted");
514
		}
515
	}
516
	
517
	// 4th round: Add TreeIndex to each taxon
518
	private boolean doPhase04(PesiExportState state) {
519
		boolean success = true;
520
		
521
		logger.info("PHASE 4: Make TreeIndex ... ");
522
	
523
		//TODO test if possible to move to phase 02 
524
		String sql = " UPDATE Taxon SET ParentTaxonFk = (Select TaxonId from Taxon where RankFk = 0) " +
525
				" WHERE (RankFk = 10) and TaxonStatusFk = 1 ";
526
		state.getConfig().getDestination().update(sql);
527
		
528
		state.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
529
		
530
		return success;
531
		
532
	}
533
	
534
	
535
	// 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
536
	private boolean doPhase02_OLD(PesiExportState state) {
537
		boolean success = true;
538
		if (! state.getConfig().isDoTreeIndex()){
539
			logger.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
540
			return success;
541
		}
542
		
543
		List<Classification> classificationList = null;
544
		logger.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
545
		
546
		// Specify starting ranks for tree traversing
547
		rankList.add(Rank.KINGDOM());
548
		rankList.add(Rank.GENUS());
549

    
550
		// Specify where to stop traversing (value) when starting at a specific Rank (key)
551
		rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
552
		rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
553
		
554
		StringBuffer treeIndex = new StringBuffer();
555
		
556
		// Retrieve list of classifications
557
		TransactionStatus txStatus = startTransaction(true);
558
		logger.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
559
		classificationList = getClassificationService().listClassifications(null, 0, null, null);
560
		commitTransaction(txStatus);
561
		logger.debug("Committed transaction.");
562

    
563
		logger.info("Fetched " + classificationList.size() + " classification(s).");
564

    
565
		setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex, "TreeIndex", "TreeIndex", "TI"));
566
		List<TaxonNode> rankSpecificRootNodes;
567
		for (Classification classification : classificationList) {
568
			for (Rank rank : rankList) {
569
				
570
				txStatus = startTransaction(true);
571
				logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
572

    
573
				rankSpecificRootNodes = getClassificationService().loadRankSpecificRootNodes(classification, rank, null);
574
				logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
575

    
576
				commitTransaction(txStatus);
577
				logger.debug("Committed transaction.");
578

    
579
				for (TaxonNode rootNode : rankSpecificRootNodes) {
580
					txStatus = startTransaction(false);
581
					Rank endRank = rank2endRankMap.get(rank);
582
					if (endRank != null) {
583
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");
584
					} else {
585
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");
586
					}
587

    
588
					TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
589

    
590
					if (isPesiTaxon(newNode.getTaxon())){
591
						TaxonNode parentNode = newNode.getParent();
592
						if (rank.equals(Rank.KINGDOM())) {
593
							treeIndex = new StringBuffer();
594
							treeIndex.append("#");
595
						} else {
596
							// Get treeIndex from parentNode
597
							if (parentNode != null) {
598
								boolean annotationFound = false;
599
								Set<Annotation> annotations = parentNode.getAnnotations();
600
								for (Annotation annotation : annotations) {
601
									AnnotationType annotationType = annotation.getAnnotationType();
602
									if (annotationType != null && annotationType.equals(getTreeIndexAnnotationType())) {
603
										treeIndex = new StringBuffer(CdmUtils.Nz(annotation.getText()));
604
										annotationFound = true;
605
	//									logger.error("treeIndex: " + treeIndex);
606
										break;
607
									}
608
								}
609
								if (!annotationFound) {
610
									// This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
611
									logger.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode.getUuid() + ", Taxon: " + parentNode.getTaxon().getUuid());
612
									treeIndex = new StringBuffer();
613
									treeIndex.append("#");
614
								}
615
							} else {
616
								// TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
617
								logger.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode.getUuid());
618
								treeIndex = new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
619
								treeIndex.append("#");
620
							}
621
						}
622
						nomenclaturalCode = newNode.getTaxon().getName().getNomenclaturalCode();
623
						kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
624
						traverseTree(newNode, parentNode, treeIndex, endRank, state);
625
						parentNode =null;
626
					}else{
627
						logger.debug("Taxon is not a PESI taxon: " + newNode.getTaxon().getUuid());
628
					}
629
					
630
					newNode = null;
631
					
632
					try {
633
						commitTransaction(txStatus);
634
						logger.debug("Committed transaction.");
635
					} catch (Exception e) {
636
						logger.error(e.getMessage());
637
						e.printStackTrace();
638
					}
639

    
640
				}
641
				rankSpecificRootNodes = null;
642
			}
643
			
644
		}
645
		
646
		logger.warn("Taking snapshot at the end of phase 2 of taxonExport");
647
		ProfilerController.memorySnapshot();
648
		return success;
649
	}	
650

    
651
	//PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
652
	private boolean doPhase03(PesiExportState state) {
653
		int count = 0;
654
		int pastCount = 0;
655
		boolean success = true;
656
		if (! state.getConfig().isDoTreeIndex()){
657
			logger.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
658
			return success;
659
		}
660
		// Get the limit for objects to save within a single transaction.
661
		int limit = state.getConfig().getLimitSave();
662

    
663
		List<TaxonBase> list;
664
		logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
665
		// Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
666
		
667
		// Start transaction
668
		TransactionStatus txStatus = startTransaction(true);
669
		logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
670
		int partitionCount = 0;
671
		while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {
672

    
673
			logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
674
			for (TaxonBase<?> taxon : list) {
675
				TaxonNameBase<?,?> taxonName = taxon.getName();
676
				// Determine expertFk
677
//				Integer expertFk = makeExpertFk(state, taxonName);
678
//
679
//				// Determine speciesExpertFk
680
//				Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
681

    
682
				doCount(count++, modCount, pluralString);
683
				Integer typeNameFk = getTypeNameFk(taxonName, state);
684
				kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
685
				
686
				//TODO why are expertFks needed? (Andreas M.)
687
//				if (expertFk != null || speciesExpertFk != null) {
688
					invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon), 
689
							typeNameFk, kingdomFk, state);
690
//				}
691
					
692
					taxon = null;
693
					taxonName = null;
694
			}
695

    
696
			// Commit transaction
697
			commitTransaction(txStatus);
698
			logger.debug("Committed transaction.");
699
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
700
			pastCount = count;
701

    
702
			// Start transaction
703
			txStatus = startTransaction(true);
704
			logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
705
		}
706
		if (list == null) {
707
			logger.info("No " + pluralString + " left to fetch.");
708
		}
709
		
710
		list = null;
711
		
712
		// Commit transaction
713
		commitTransaction(txStatus);
714
		
715
		logger.debug("Committed transaction.");
716
		logger.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount);
717
		ProfilerController.memorySnapshot();
718
		return success;
719
	}
720
	
721
	//	"PHASE 5: Creating Inferred Synonyms..."
722
	private boolean doPhase05(PesiExportState state, PesiExportMapping mapping, PesiExportMapping synRelMapping) throws SQLException {
723
		int count;
724
		int pastCount;
725
		boolean success = true;
726
		// Get the limit for objects to save within a single transaction.
727
		if (! state.getConfig().isDoInferredSynonyms()){
728
			logger.info ("Ignore PHASE 5: Creating Inferred Synonyms...");
729
			return success;
730
		}
731
		
732
		int limit = state.getConfig().getLimitSave();
733
		// Create inferred synonyms for accepted taxa
734
		logger.info("PHASE 4: Creating Inferred Synonyms...");
735

    
736
		// Determine the count of elements in datawarehouse database table Taxon
737
		currentTaxonId = determineTaxonCount(state);
738
		currentTaxonId++;
739

    
740
		count = 0;
741
		pastCount = 0;
742
		int pageSize = limit;
743
		int pageNumber = 1;
744
		String inferredSynonymPluralString = "Inferred Synonyms";
745
		
746
		// Start transaction
747
		TransactionStatus txStatus = startTransaction(true);
748
		logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
749
		List<TaxonBase> taxonList = null;
750
		
751
		
752
		
753
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SPECIES(), pageSize, pageNumber)).size() > 0) {
754
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
755

    
756
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
757
			inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
758
					synRelMapping, taxonList));
759
			
760
			doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
761
			// Commit transaction
762
			commitTransaction(txStatus);
763
			logger.debug("Committed transaction.");
764
			logger.info("Exported " + (taxonList.size()) + " " + inferredSynonymPluralString + ". Total: " + count);
765
			//pastCount = count;
766
			
767
			// Save Rank Data and KingdomFk for inferred synonyms
768
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
769
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);
770
			}
771

    
772
			// Start transaction
773
			txStatus = startTransaction(true);
774
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
775
			
776
			// Increment pageNumber
777
			pageNumber++;
778
		}
779
		
780
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SUBSPECIES(), pageSize, pageNumber)).size() > 0) {
781
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
782

    
783
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
784
			inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
785
					synRelMapping, taxonList));
786
			;
787
			doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
788
			// Commit transaction
789
			commitTransaction(txStatus);
790
			logger.debug("Committed transaction.");
791
			logger.info("Exported " + taxonList.size()+ " " + inferredSynonymPluralString + ". Total: " + count);
792
			//pastCount = count;
793
			
794
			// Save Rank Data and KingdomFk for inferred synonyms
795
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
796
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);
797
			}
798

    
799
			// Start transaction
800
			txStatus = startTransaction(true);
801
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
802
			
803
			// Increment pageNumber
804
			pageNumber++;
805
		}
806
		if (taxonList.size() == 0) {
807
			logger.info("No " + parentPluralString + " left to fetch.");
808
		}
809
		
810
		taxonList = null;
811
//		logger.warn("Taking snapshot at the end of phase 4 of taxonExport");
812
//		ProfilerController.memorySnapshot();
813
		
814
		// Commit transaction
815
		commitTransaction(txStatus);
816
		System.gc();
817
		logger.debug("Taking snapshot at the end of phase 4 after gc() of taxonExport");
818
		ProfilerController.memorySnapshot();
819
		logger.debug("Committed transaction.");
820
		return success;
821
	}
822

    
823
	/**
824
	 * @param state
825
	 * @param mapping
826
	 * @param synRelMapping
827
	 * @param currentTaxonId
828
	 * @param taxonList
829
	 * @param inferredSynonymsDataToBeSaved
830
	 * @return
831
	 */
832
	private HashMap<Integer, TaxonNameBase<?, ?>> createInferredSynonymsForTaxonList(PesiExportState state,
833
			PesiExportMapping mapping, PesiExportMapping synRelMapping,	 List<TaxonBase> taxonList) {
834
		
835
		Taxon acceptedTaxon;
836
		Classification classification = null;
837
		List<Synonym> inferredSynonyms = null;
838
		boolean localSuccess = true;
839
		
840
		HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
841
		
842
		for (TaxonBase<?> taxonBase : taxonList) {
843
		
844
			if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
845
				acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
846
				TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
847
				
848
				if (taxonName.isInstanceOf(ZoologicalName.class)) {
849
					nomenclaturalCode  = taxonName.getNomenclaturalCode();
850
					kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
851

    
852
					Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();
853
					TaxonNode singleNode = null;
854
					
855
					if (taxonNodes.size() > 0) {
856
						// Determine the classification of the current TaxonNode
857
						
858
						singleNode = taxonNodes.iterator().next();
859
						if (singleNode != null) {
860
							classification = singleNode.getClassification();
861
						} else {
862
							logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");
863
						}
864
					} else {
865
						// Classification could not be determined directly from this TaxonNode
866
						// The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
867
						if (taxonNodes.size() == 0) {
868
							logger.error("Classification could not be determined directly from this Taxon: " + acceptedTaxon.getUuid() + " is misapplication? "+acceptedTaxon.isMisapplication()+ "). The classification of the last taxon is used");
869
						
870
						}
871
					}
872
					
873
					if (classification != null) {
874
						try{
875
							TaxonNameBase name = acceptedTaxon.getName();
876
							//if (name.isSpecies() || name.isInfraSpecific()){
877
								inferredSynonyms  = getTaxonService().createAllInferredSynonyms(acceptedTaxon, classification, true);
878
							//}
879
//								inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
880
							if (inferredSynonyms != null) {
881
								for (Synonym synonym : inferredSynonyms) {
882
//									TaxonNameBase<?,?> synonymName = synonym.getName();
883
									MarkerType markerType =getUuidMarkerType(PesiTransformer.uuidMarkerGuidIsMissing, state);
884
									synonym.addMarker(Marker.NewInstance(markerType, true));
885
									// Both Synonym and its TaxonName have no valid Id yet
886
									synonym.setId(currentTaxonId++);
887
									
888
									
889
									localSuccess &= mapping.invoke(synonym);
890
									//get SynonymRelationship and export
891
									if (synonym.getSynonymRelations().isEmpty() ){
892
										SynonymRelationship synRel;					
893
										IdentifiableSource source = synonym.getSources().iterator().next();
894
										if (source.getIdNamespace().contains("Potential combination")){
895
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
896
											logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to potential combination");
897
										} else if (source.getIdNamespace().contains("Inferred Genus")){
898
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_GENUS_OF());
899
											logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred genus");
900
										} else if (source.getIdNamespace().contains("Inferred Epithet")){
901
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_EPITHET_OF());
902
											logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred epithet");
903
										} else{
904
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_SYNONYM_OF());
905
											logger.error(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred synonym");
906
										}
907
										
908
										localSuccess &= synRelMapping.invoke(synRel);
909
										if (!localSuccess) {
910
											logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
911
										}
912
										synRel = null;
913
									} else {
914
										for (SynonymRelationship synRel: synonym.getSynonymRelations()){
915
											localSuccess &= synRelMapping.invoke(synRel);
916
											if (!localSuccess) {
917
												logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
918
											} else {
919
												logger.info("Synonym relationship successfully exported: " + synonym.getTitleCache() + "  " +acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
920
											}
921
											synRel = null;
922
										}
923
									}
924
									
925
									inferredSynonymsDataToBeSaved.put(synonym.getId(), synonym.getName());
926
								}
927
							}
928
						}catch(Exception e){
929
							logger.error(e.getMessage());
930
							e.printStackTrace();
931
						}
932
					} else {
933
						logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");
934
					}
935
				} else {
936
//							logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
937
				}
938
			} else {
939
				logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");
940
			}
941
		}
942
		return inferredSynonymsDataToBeSaved;
943
	}
944
	
945

    
946
	/**
947
	 * Handles names that do not appear in taxa
948
	 * @param state
949
	 * @param mapping
950
	 * @return
951
	 */
952
	private boolean doNames(PesiExportState state, PesiExportMapping additionalSourceMapping)  throws SQLException {
953
		
954
		boolean success = true;
955
		if (! state.getConfig().isDoPureNames()){
956
			logger.info ("Ignore PHASE 1b: PureNames");
957
			return success;
958
		}
959
		
960
		try {
961
			PesiExportMapping mapping = getPureNameMapping(state);
962
			mapping.initialize(state);
963
			int count = 0;
964
			int pastCount = 0;
965
			List<NonViralName<?>> list;
966
			success = true;
967
			// Get the limit for objects to save within a single transaction.
968
			int limit = state.getConfig().getLimitSave();
969

    
970
			
971
			logger.info("PHASE 1b: Export Pure Names ...");
972
			// Start transaction
973
			TransactionStatus txStatus = startTransaction(true);
974
			logger.info("Started new transaction for Pure Names. Fetching some " + pluralString + " (max: " + limit + ") ...");
975
			
976
			int partitionCount = 0;
977
			while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {
978

    
979
				logger.info("Fetched " + list.size() + " names without taxa. Exporting...");
980
				for (TaxonNameBase<?,?> taxonName : list) {
981
					doCount(count++, modCount, pluralString);
982
					success &= mapping.invoke(taxonName);
983
					//additional source
984
					if (taxonName.getNomenclaturalReference() != null || StringUtils.isNotBlank(taxonName.getNomenclaturalMicroReference() )){
985
						additionalSourceMapping.invoke(taxonName);
986
					}
987
				}
988

    
989
				// Commit transaction
990
				commitTransaction(txStatus);
991
				logger.debug("Committed transaction.");
992
				logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
993
				pastCount = count;
994

    
995
				// Start transaction
996
				txStatus = startTransaction(true);
997
				logger.info("Started new transaction for PureNames. Fetching some " + pluralString + " (max: " + limit + ") ...");
998
			}
999
			if (list == null) {
1000
				logger.info("No " + pluralString + " left to fetch.");
1001
			}
1002
			// Commit transaction
1003
			commitTransaction(txStatus);
1004
			logger.debug("Committed transaction.");
1005
		} catch (Exception e) {
1006
			logger.error("Error occurred in pure name export");
1007
			e.printStackTrace();
1008
			success = false;
1009
		}
1010
		return success;
1011
	}
1012

    
1013
	/**
1014
	 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
1015
	 * @param state The {@link PesiExportState PesiExportState}.
1016
	 * @return The count.
1017
	 */
1018
	private Integer determineTaxonCount(PesiExportState state) {
1019
		Integer result = null;
1020
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
1021
		
1022
		String sql;
1023
		Source destination =  pesiConfig.getDestination();
1024
		sql = "SELECT max(taxonId) FROM Taxon";
1025
		destination.setQuery(sql);
1026
		ResultSet resultSet = destination.getResultSet();
1027
		try {
1028
			resultSet.next();
1029
			result = resultSet.getInt(1);
1030
		} catch (SQLException e) {
1031
			logger.error("TaxonCount could not be determined: " + e.getMessage());
1032
			e.printStackTrace();
1033
		}
1034
		return result;
1035
	}
1036
	
1037
	/**
1038
	 * Checks whether a parent at specific level has a specific Rank.
1039
	 * @param taxonName A {@link TaxonNameBase TaxonName}.
1040
	 * @param level The ancestor level.
1041
	 * @param ancestorRank The ancestor rank.
1042
	 * @return Whether a parent at a specific level has a specific Rank.
1043
	 */
1044
	private boolean validateAncestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {
1045
		boolean result = false;
1046
		TaxonNode parentNode = null;
1047
		if (taxonBase.isInstanceOf(Taxon.class)){
1048
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1049
			// Get ancestor Taxon via TaxonNode
1050
			Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
1051
			if (taxonNodes.size() == 1) {
1052
				TaxonNode taxonNode = taxonNodes.iterator().next();
1053
				if (taxonNode != null) {
1054
					for (int i = 0; i < level; i++) {
1055
						if (taxonNode != null) {
1056
							taxonNode  = taxonNode.getParent();
1057
						}
1058
					}
1059
					parentNode = taxonNode;
1060
				}
1061
			} else if (taxonNodes.size() > 1) {
1062
				logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1063
			}
1064
		}
1065
		//compare
1066
		if (parentNode != null) {
1067
			TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);
1068
			Taxon parentTaxon = node.getTaxon();
1069
			if (parentTaxon != null) {
1070
				TaxonNameBase<?,?> parentTaxonName = parentTaxon.getName();
1071
				if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {
1072
					result = true;
1073
				}
1074
			} else {
1075
				logger.error("This TaxonNode has no Taxon: " + node.getUuid());
1076
			}
1077
		}
1078
		return result;
1079
	}
1080

    
1081
	/**
1082
	 * Returns the AnnotationType for a given UUID.
1083
	 * @param uuid The Annotation UUID.
1084
	 * @param label The Annotation label.
1085
	 * @param text The Annotation text.
1086
	 * @param labelAbbrev The Annotation label abbreviation.
1087
	 * @return The AnnotationType.
1088
	 */
1089
	protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){
1090
		AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);
1091
		if (annotationType == null) {
1092
			annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
1093
			annotationType.setUuid(uuid);
1094
//			annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1095
			getTermService().save(annotationType);
1096
		}
1097
		return annotationType;
1098
	}
1099

    
1100
	/**
1101
	 * Traverses the classification recursively and stores determined values for every Taxon.
1102
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1103
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1104
	 * @param treeIndex The TreeIndex at the current level.
1105
	 * @param fetchLevel Rank to stop fetching at.
1106
	 * @param state The {@link PesiExportState PesiExportState}.
1107
	 */
1108
	private void traverseTree(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, Rank fetchLevel, PesiExportState state) {
1109
		// Traverse all branches from this childNode until specified fetchLevel is reached.
1110
		StringBuffer localTreeIndex = new StringBuffer(treeIndex);
1111
		Taxon childTaxon = childNode.getTaxon();
1112
		if (childTaxon != null) {
1113
			if (isPesiTaxon(childTaxon)){
1114
				Integer taxonId = state.getDbId(childTaxon);
1115
				TaxonNameBase<?,?> childName = childTaxon.getName();
1116
				if (taxonId != null) {
1117
					Rank childRank = childName.getRank();
1118
					if (childRank != null) {
1119
						if (! childRank.equals(fetchLevel)) {
1120
	
1121
							localTreeIndex.append(taxonId + "#");
1122
							
1123
							saveData(childNode, parentNode, localTreeIndex, state, taxonId);
1124
	
1125
							// Store treeIndex as annotation for further use
1126
							Annotation annotation = Annotation.NewInstance(localTreeIndex.toString(), getTreeIndexAnnotationType(), Language.DEFAULT());
1127
							childNode.addAnnotation(annotation);
1128
	
1129
							for (TaxonNode newNode : childNode.getChildNodes()) {
1130
								if (newNode.getTaxon() != null && isPesiTaxon(newNode.getTaxon())){
1131
									traverseTree(newNode, childNode, localTreeIndex, fetchLevel, state);
1132
								}
1133
							}
1134
							
1135
						} else {
1136
	//						logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1137
							return;
1138
						}
1139
					} else {
1140
						logger.error("Rank is NULL. FetchLevel can not be checked: " + childName.getUuid() + " (" + childName.getTitleCache() + ")");
1141
					}
1142
				} else {
1143
					logger.error("Taxon can not be found in state: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
1144
				}
1145
			}else{
1146
				if (logger.isDebugEnabled()){ 
1147
					logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
1148
				}
1149
			}
1150

    
1151
		} else {
1152
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
1153
		}
1154
	}
1155

    
1156
	/**
1157
	 * Stores values in database for every recursive round.
1158
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1159
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1160
	 * @param treeIndex The TreeIndex at the current level.
1161
	 * @param state The {@link PesiExportState PesiExportState}.
1162
	 * @param currentTaxonFk The TaxonFk to store the values for.
1163
	 */
1164
	private void saveData(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, PesiExportState state, Integer currentTaxonFk) {
1165
		// We are differentiating kingdoms by the nomenclatural code for now.
1166
		// This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1167
		Taxon childTaxon = childNode.getTaxon();
1168
		if (isPesiTaxon(childTaxon)) {
1169
			TaxonBase<?> parentTaxon = null;
1170
			if (parentNode != null) {
1171
				parentTaxon = parentNode.getTaxon();
1172
				
1173
			}
1174

    
1175
			invokeParentTaxonFkAndTreeIndex(state.getDbId(parentTaxon), currentTaxonFk,	treeIndex);
1176
		}
1177
		
1178
	}
1179

    
1180
	/**
1181
	 * Inserts values into the Taxon database table.
1182
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1183
	 * @param state The {@link PesiExportState PesiExportState}.
1184
	 * @param stmt The prepared statement.
1185
	 * @return Whether save was successful or not.
1186
	 */
1187
	protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk, Integer currentTaxonFk, StringBuffer treeIndex) {
1188
		try {
1189
			if (parentTaxonFk != null) {
1190
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(1, parentTaxonFk);
1191
			} else {
1192
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(1, null);
1193
			}
1194

    
1195
			if (treeIndex != null) {
1196
				parentTaxonFk_TreeIndex_KingdomFkStmt.setString(2, treeIndex.toString());
1197
			} else {
1198
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(2, null);
1199
			}
1200

    
1201
			if (currentTaxonFk != null) {
1202
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(3, currentTaxonFk);
1203
			} else {
1204
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(3, null);
1205
			}
1206
			
1207
			parentTaxonFk_TreeIndex_KingdomFkStmt.executeUpdate();
1208
			return true;
1209
		} catch (SQLException e) {
1210
			logger.error("ParentTaxonFk (" + parentTaxonFk ==null? "-":parentTaxonFk + ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk == null? "-" :currentTaxonFk) + ": " + e.getMessage());
1211
			e.printStackTrace();
1212
			return false;
1213
		}
1214
	}
1215
	
1216
	protected boolean invokeParentTaxonFk(Integer parentId, Integer childId) {
1217
		try {
1218
			parentTaxonFkStmt.setInt(1, parentId);
1219
			parentTaxonFkStmt.setInt(2, childId);
1220
			parentTaxonFkStmt.executeUpdate();
1221
			return true;
1222
		} catch (SQLException e) {
1223
			logger.warn("ParentTaxonFk (" + parentId ==null? "-":parentId + ") could not be inserted into database for taxon "+ (childId == null? "-" :childId) + ": " + e.getMessage());
1224
			e.printStackTrace();
1225
			return false;
1226
		}
1227
	}
1228

    
1229

    
1230
	/**
1231
	 * Inserts Rank data and KingdomFk into the Taxon database table.
1232
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1233
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1234
	 * @param taxonFk The TaxonFk to store the values for.
1235
	 * @param state 
1236
	 * @param kindomFk The KingdomFk.
1237
	 * @return Whether save was successful or not.
1238
	 */
1239
	private boolean invokeRankDataAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, Integer taxonFk, Integer kingdomFk, PesiExportState state) {
1240
		try {
1241
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1242
			if (rankFk != null) {
1243
				rankUpdateStmt.setInt(1, rankFk);
1244
			} else {
1245
				rankUpdateStmt.setObject(1, null);
1246
			}
1247
	
1248
			String rankCache = getRankCache(taxonName, nomenclaturalCode, state);
1249
			if (rankCache != null) {
1250
				rankUpdateStmt.setString(2, rankCache);
1251
			} else {
1252
				rankUpdateStmt.setObject(2, null);
1253
			}
1254
			
1255
			if (kingdomFk != null) {
1256
				rankUpdateStmt.setInt(3, kingdomFk);
1257
			} else {
1258
				rankUpdateStmt.setObject(3, null);
1259
			}
1260
			
1261
			if (taxonFk != null) {
1262
				rankUpdateStmt.setInt(4, taxonFk);
1263
			} else {
1264
				rankUpdateStmt.setObject(4, null);
1265
			}
1266
			
1267
			rankUpdateStmt.executeUpdate();
1268
			return true;
1269
		} catch (SQLException e) {
1270
			logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());
1271
			e.printStackTrace();
1272
			return false;
1273
		}
1274
	}
1275

    
1276
	/**
1277
	 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1278
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1279
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1280
	 * @param taxonFk The TaxonFk to store the values for.
1281
	 * @param typeNameFk The TypeNameFk.
1282
	 * @param state 
1283
	 * @param kindomFk The KingdomFk.
1284
	 * @param expertFk The ExpertFk.
1285
	 * @param speciesExpertFk The SpeciesExpertFk.
1286
	 * @return Whether save was successful or not.
1287
	 */
1288
	private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, 
1289
			Integer taxonFk, Integer typeNameFk, Integer kingdomFkk, PesiExportState state) {
1290
		try {
1291
			int index = 1;
1292
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1293
			if (rankFk != null) {
1294
				rankTypeExpertsUpdateStmt.setInt(index++, rankFk);
1295
			} else {
1296
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1297
			}
1298
	
1299
			String rankCache = getRankCache(taxonName, nomenclaturalCode, state);
1300
			if (rankCache != null) {
1301
				rankTypeExpertsUpdateStmt.setString(index++, rankCache);
1302
			} else {
1303
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1304
			}
1305
			
1306
			if (typeNameFk != null) {
1307
				rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);
1308
			} else {
1309
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1310
			}
1311
			
1312
			if (kingdomFk != null) {
1313
				rankTypeExpertsUpdateStmt.setInt(index++, kingdomFk);
1314
			} else {
1315
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1316
			}
1317
			
1318
//			if (expertFk != null) {
1319
//				rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1320
//			} else {
1321
//				rankTypeExpertsUpdateStmt.setObject(5, null);
1322
//			}
1323
//
1324
//			//TODO handle experts GUIDS
1325
//			if (speciesExpertFk != null) {
1326
//				rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1327
//			} else {
1328
//				rankTypeExpertsUpdateStmt.setObject(6, null);
1329
//			}
1330
//			
1331
			if (taxonFk != null) {
1332
				rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);
1333
			} else {
1334
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1335
			}
1336

    
1337
			rankTypeExpertsUpdateStmt.executeUpdate();
1338
			return true;
1339
		} catch (SQLException e) {
1340
			logger.error("Data could not be inserted into database: " + e.getMessage());
1341
			e.printStackTrace();
1342
			return false;
1343
		} catch (Exception e) {
1344
			logger.error("Some exception occurred: " + e.getMessage());
1345
			e.printStackTrace();
1346
			return false;
1347
		}
1348
	}
1349

    
1350
	/**
1351
	 * Deletes all entries of database tables related to <code>Taxon</code>.
1352
	 * @param state The {@link PesiExportState PesiExportState}.
1353
	 * @return Whether the delete operation was successful or not.
1354
	 */
1355
	protected boolean doDelete(PesiExportState state) {
1356
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
1357
		
1358
		String sql;
1359
		Source destination =  pesiConfig.getDestination();
1360

    
1361
		// Clear Taxon
1362
		sql = "DELETE FROM " + dbTableName;
1363
		destination.setQuery(sql);
1364
		destination.update(sql);
1365
		return true;
1366
	}
1367

    
1368
	/* (non-Javadoc)
1369
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1370
	 */
1371
	@Override
1372
	protected boolean isIgnore(PesiExportState state) {
1373
		return ! state.getConfig().isDoTaxa();
1374
	}
1375

    
1376
	
1377
	/**
1378
	 * Creates the kingdom fk.
1379
	 * @param taxonName
1380
	 * @return
1381
	 */
1382
	@SuppressWarnings("unused")  //used by mapper
1383
	private static Integer getKingdomFk(TaxonNameBase taxonName){
1384
		return PesiTransformer.nomenClaturalCode2Kingdom(taxonName.getNomenclaturalCode());
1385
	}
1386
	
1387
	/**
1388
	 * Creates the parent fk.
1389
	 * @param taxonName
1390
	 * @return
1391
	 */
1392
	@SuppressWarnings("unused")  //used by mapper
1393
	private static Integer getParentTaxonFk(TaxonBase<?> taxonBase, PesiExportState state){
1394
		if (taxonBase.isInstanceOf(Taxon.class)){
1395
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1396
			if (! isMisappliedName(taxon)){
1397
				Set<TaxonNode> nodes = taxon.getTaxonNodes();
1398
				if (nodes.size() == 0){
1399
					if (taxon.getName().getRank().isLower(Rank.KINGDOM())){
1400
						logger.warn("Accepted taxon has no parent. " + taxon.getTitleCache() + ", " +  taxon.getUuid());
1401
					}
1402
				}else if (nodes.size() > 1){
1403
					logger.warn("Taxon has more than 1 node attached. This is not supported by PESI export." +  taxon.getTitleCache() + ", " +  taxon.getUuid());
1404
				}else{
1405
					Taxon parent =nodes.iterator().next().getParent().getTaxon();
1406
					return state.getDbId(parent);
1407
				}
1408
			}
1409
		}
1410
		return null;
1411
	}
1412

    
1413
	/**
1414
	 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1415
	 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1416
	 * @param taxonName
1417
	 * @return
1418
	 */
1419
	@SuppressWarnings("unused")  //used by mapper
1420
	private static Integer getRankFk(TaxonNameBase<?,?> taxonName) {
1421
		return getRankFk(taxonName, taxonName.getNomenclaturalCode());
1422
	}
1423
		
1424
	
1425
	/**
1426
	 * Returns the <code>RankFk</code> attribute.
1427
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1428
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1429
	 * @return The <code>RankFk</code> attribute.
1430
	 * @see MethodMapper
1431
	 */
1432
	private static Integer getRankFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1433
		Integer result = null;
1434
		try {
1435
			if (nomenclaturalCode != null) {
1436
				if (taxonName != null) {
1437
					if (taxonName.getRank() == null) {
1438
						logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1439
					} else {
1440
						result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1441
					}
1442
					if (result == null) {
1443
						logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1444
					}
1445
				}
1446
			}
1447
		} catch (Exception e) {
1448
			e.printStackTrace();
1449
		}
1450
		return result;
1451
	}
1452

    
1453
	/**
1454
	 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1455
	 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1456
	 * @param taxonName
1457
	 * @return
1458
	 */
1459
	@SuppressWarnings("unused")  //used by mapper
1460
	private static String getRankCache(TaxonNameBase<?,?> taxonName, PesiExportState state) {
1461
		return getRankCache(taxonName, taxonName.getNomenclaturalCode(), state);
1462
	}
1463

    
1464
	
1465
	/**
1466
	 * Returns the <code>RankCache</code> attribute.
1467
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1468
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1469
	 * @param state 
1470
	 * @return The <code>RankCache</code> attribute.
1471
	 * @see MethodMapper
1472
	 */
1473
	private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, PesiExportState state) {
1474
		if (nomenclaturalCode != null) {
1475
			return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1476
		}else{
1477
			logger.warn("No nomenclatural code defined for name " + taxonName.getUuid());
1478
			return null;
1479
		}
1480
		
1481
	}
1482

    
1483
	
1484
	/**
1485
	 * Returns the <code>DisplayName</code> attribute.
1486
	 * @param taxon The {@link TaxonBase Taxon}.
1487
	 * @return The <code>DisplayName</code> attribute.
1488
	 * @see MethodMapper
1489
	 */
1490
	@SuppressWarnings("unused")  //used by Mapper
1491
	private static String getDisplayName(TaxonBase<?> taxon) {
1492
		TaxonNameBase<?,?> taxonName = taxon.getName();
1493
		String result = getDisplayName(taxonName);
1494
		if (isMisappliedName(taxon)){
1495
			result = result + " " + getAuthorString(taxon);
1496
		}
1497
		return result;
1498
	}
1499
	
1500
	/**
1501
	 * Returns the <code>AuthorString</code> attribute.
1502
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1503
	 * @return The <code>AuthorString</code> attribute.
1504
	 * @see MethodMapper
1505
	 */
1506
	@SuppressWarnings("unused") //used by mapper
1507
	protected static String getAuthorString(TaxonBase<?> taxon) {
1508
		try {
1509
			String result = null;
1510
			boolean isNonViralName = false;
1511
			String authorshipCache = null;
1512
			TaxonNameBase<?,?> taxonName = taxon.getName();
1513
			if (taxonName != null && taxonName.isInstanceOf(NonViralName.class)){
1514
				authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();
1515
				isNonViralName = true;
1516
			}
1517
			result = authorshipCache;
1518
			
1519
			// For a misapplied names there are special rules
1520
			if (isMisappliedName(taxon)){
1521
				if (taxon.getSec() != null){
1522
					String secTitle = taxon.getSec().getTitleCache();
1523
					if (! secTitle.startsWith("auct")){
1524
						secTitle = "sensu " + secTitle;
1525
					}else if (secTitle.equals("auct")){  //may be removed once the title cache is generated correctly for references with title auct. #
1526
						secTitle = "auct.";
1527
					}
1528
					return secTitle;
1529
				}else if (StringUtils.isBlank(authorshipCache)) {
1530
					// Set authorshipCache to "auct."
1531
					result = PesiTransformer.AUCT_STRING;
1532
				}else{
1533
					result = PesiTransformer.AUCT_STRING;
1534
//					result = authorshipCache;
1535
				}
1536
			}
1537
			
1538
			if (taxonName == null){
1539
				logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1540
			}else if (! isNonViralName){
1541
				logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1542
			}
1543
			
1544
			if (StringUtils.isBlank(result)) {
1545
				return null;
1546
			} else {
1547
				return result;
1548
			}
1549
		} catch (Exception e) {
1550
			e.printStackTrace();
1551
			return null;
1552
		}
1553
		
1554
	}
1555
		
1556
	
1557
	/**
1558
	 * Returns the <code>DisplayName</code> attribute.
1559
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1560
	 * @return The <code>DisplayName</code> attribute.
1561
	 * @see MethodMapper
1562
	 */
1563
	@SuppressWarnings("unused")  //used by Mapper
1564
	private static String getDisplayName(TaxonNameBase<?,?> taxonName) {
1565
		// TODO: extension?
1566
		if (taxonName == null) {
1567
			return null;
1568
		}else{
1569
			INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1570
			HTMLTagRules tagRules = new HTMLTagRules().
1571
					addRule(TagEnum.name, "i").
1572
					addRule(TagEnum.nomStatus, "@status@");
1573
			
1574
			NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1575
			String result = cacheStrategy.getFullTitleCache(nvn, tagRules);
1576
			cacheStrategy = null;
1577
			nvn = null;
1578
			return result.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");
1579
		}
1580
	}
1581
	
1582

    
1583
	/**
1584
	 * Returns the <code>WebShowName</code> attribute for a taxon.
1585
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1586
	 * @return The <code>WebShowName</code> attribute.
1587
	 * @see MethodMapper
1588
	*/
1589
	@SuppressWarnings("unused")
1590
	private static String getWebShowName(TaxonBase<?> taxon) {
1591
		TaxonNameBase<?,?> taxonName = taxon.getName();
1592
		String result = getWebShowName(taxonName);
1593
		if (isMisappliedName(taxon)){
1594
			result = result + " " + getAuthorString(taxon);
1595
		}
1596
		return result;
1597
	}
1598
	
1599
	/**
1600
	 * Returns the <code>WebShowName</code> attribute.
1601
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1602
	 * @return The <code>WebShowName</code> attribute.
1603
	 * @see MethodMapper
1604
	 */
1605
	private static String getWebShowName(TaxonNameBase<?,?> taxonName) {
1606
		//TODO extensions?
1607
		if (taxonName == null) {
1608
			return null;
1609
		}else{
1610
			INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1611
		
1612
			HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");
1613
			NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1614
			String result = cacheStrategy.getTitleCache(nvn, tagRules);
1615
			cacheStrategy = null;
1616
			nvn = null;
1617
			return result;
1618
		}
1619
	}
1620

    
1621
 	
1622
	/**
1623
	 * Returns the <code>WebSearchName</code> attribute.
1624
	 * @param taxonName The {@link NonViralName NonViralName}.
1625
	 * @return The <code>WebSearchName</code> attribute.
1626
	 * @see MethodMapper
1627
	 */
1628
	@SuppressWarnings("unused")
1629
	private static String getWebSearchName(TaxonNameBase<?,?> taxonName) {
1630
		//TODO extensions?
1631
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1632
		NonViralNameDefaultCacheStrategy<NonViralName<?>> strategy = getCacheStrategy(nvn);
1633
		String result = strategy.getNameCache(nvn);
1634
		strategy = null;
1635
		nvn = null;
1636
		return result;
1637
	}
1638

    
1639

    
1640
	/**
1641
	 * Returns the <code>FullName</code> attribute.
1642
	 * @param taxonName The {@link NonViralName NonViralName}.
1643
	 * @return The <code>FullName</code> attribute.
1644
	 * @see MethodMapper
1645
	 */
1646
	@SuppressWarnings("unused")
1647
	private static String getFullName(TaxonNameBase taxonName) {
1648
		//TODO extensions?
1649
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1650
		String result = getCacheStrategy(nvn).getTitleCache(nvn);
1651
		Iterator<TaxonBase> taxa = taxonName.getTaxa().iterator();
1652
		if (taxonName.getTaxa().size() >0){
1653
			if (taxonName.getTaxa().size() == 1){
1654
				TaxonBase taxon = taxa.next();
1655
				if (isMisappliedName(taxon)){
1656
					result = result + " " + getAuthorString(taxon);
1657
				}
1658
				taxon = null;
1659
			}
1660
		}
1661
		taxa = null;
1662
		nvn = null;
1663
		return result;
1664
	}
1665
	
1666
	/**
1667
	 * Returns the <code>FullName</code> attribute.
1668
	 * @param taxon The {@link TaxonBase taxon}.
1669
	 * @return The <code>FullName</code> attribute.
1670
	 * @see MethodMapper
1671
	 */
1672
	/*@SuppressWarnings("unused")
1673
	private static String getFullName(TaxonBase taxon) {
1674
		//TODO extensions?
1675
		TaxonNameBase name = taxon.getName();
1676
		String result = getFullName(name);
1677
		if (isMisappliedName(taxon)){
1678
			result = result + " " + getAuthorString(taxon);
1679
		}
1680
		
1681
		return result;
1682
	}
1683
*/
1684
	
1685
	/**
1686
	 * Returns the nomenclatural reference which is the reference
1687
	 * including the detail (microreference).
1688
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1689
	 * @return The <code>AuthorString</code> attribute.
1690
	 * @see MethodMapper
1691
	 */
1692
	@SuppressWarnings("unused")
1693
	private static String getNomRefString(TaxonNameBase<?,?> taxonName) {
1694
		INomenclaturalReference ref = taxonName.getNomenclaturalReference();
1695
		return ref == null ? null : ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());
1696
	}
1697
	
1698

    
1699
	/**
1700
	 * Returns the <code>NameStatusFk</code> attribute.
1701
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1702
	 * @return The <code>NameStatusFk</code> attribute.
1703
	 * @see MethodMapper
1704
	 */
1705
	@SuppressWarnings("unused")
1706
	private static Integer getNameStatusFk(TaxonNameBase<?,?> taxonName) {
1707
		Integer result = null;
1708

    
1709
		NomenclaturalStatus state = getNameStatus(taxonName);
1710
		if (state != null) {
1711
			result = PesiTransformer.nomStatus2nomStatusFk(state.getType());
1712
		}
1713
		return result;
1714
	}
1715
	
1716
	/**
1717
	 * Returns the <code>NameStatusCache</code> attribute.
1718
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1719
	 * @return The <code>NameStatusCache</code> attribute.
1720
	 * @throws UndefinedTransformerMethodException 
1721
	 * @see MethodMapper
1722
	 */
1723
	@SuppressWarnings("unused")
1724
	private static String getNameStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1725
		String result = null;
1726
		NomenclaturalStatus status = getNameStatus(taxonName);
1727
		if (status != null) {
1728
			result = state.getTransformer().getCacheByNomStatus(status.getType());
1729
		}
1730
		return result;
1731
	}
1732
	
1733
	
1734
	private static NomenclaturalStatus getNameStatus(TaxonNameBase<?,?> taxonName) {
1735
		try {
1736
			if (taxonName != null && (taxonName.isInstanceOf(NonViralName.class))) {
1737
				NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);
1738
				Set<NomenclaturalStatus> states = nonViralName.getStatus();
1739
				if (states.size() == 1) {
1740
					NomenclaturalStatus status = states.iterator().next();
1741
					return status;
1742
				} else if (states.size() > 1) {
1743
					logger.error("This TaxonName has more than one Nomenclatural Status: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1744
				}
1745
			}
1746
		
1747
		} catch (Exception e) {
1748
			e.printStackTrace();
1749
		}
1750
		return null;
1751
	}
1752
	/**
1753
	 * Returns the <code>TaxonStatusFk</code> attribute.
1754
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1755
	 * @param state The {@link PesiExportState PesiExportState}.
1756
	 * @return The <code>TaxonStatusFk</code> attribute.
1757
	 * @see MethodMapper
1758
	 */
1759
	private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {
1760
		Integer result = null;
1761
		
1762
		try {
1763
			if (isMisappliedName(taxon)) {
1764
				Synonym synonym = Synonym.NewInstance(null, null);
1765
				
1766
				// This works as long as only the instance is important to differentiate between TaxonStatus.
1767
				result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in Datawarehouse now.
1768
			} else {
1769
				result = PesiTransformer.taxonBase2statusFk(taxon);
1770
			}
1771
		
1772
		} catch (Exception e) {
1773
			e.printStackTrace();
1774
		}
1775
		return result;
1776
	}
1777
	
1778
	/**
1779
	 * Returns the <code>TaxonStatusCache</code> attribute.
1780
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1781
	 * @param state The {@link PesiExportState PesiExportState}.
1782
	 * @return The <code>TaxonStatusCache</code> attribute.
1783
	 * @throws UndefinedTransformerMethodException 
1784
	 * @see MethodMapper
1785
	 */
1786
	@SuppressWarnings("unused")
1787
	private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) throws UndefinedTransformerMethodException {
1788
		return state.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon, state));
1789
	}
1790
	
1791
	/**
1792
	 * Returns the <code>TypeNameFk</code> attribute.
1793
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1794
	 * @param state The {@link PesiExportState PesiExportState}.
1795
	 * @return The <code>TypeNameFk</code> attribute.
1796
	 * @see MethodMapper
1797
	 */
1798
	private static Integer getTypeNameFk(TaxonNameBase<?,?> taxonNameBase, PesiExportState state) {
1799
		Integer result = null;
1800
		if (taxonNameBase != null) {
1801
			Set<NameTypeDesignation> nameTypeDesignations = taxonNameBase.getNameTypeDesignations();
1802
			if (nameTypeDesignations.size() == 1) {
1803
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1804
				if (nameTypeDesignation != null) {
1805
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1806
					if (typeName != null) {
1807
						result = state.getDbId(typeName);
1808
					}
1809
				}
1810
			} else if (nameTypeDesignations.size() > 1) {
1811
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonNameBase.getUuid() + " (" + taxonNameBase.getTitleCache() + ")");
1812
			}
1813
		}
1814
		return result;
1815
	}
1816
	
1817
	/**
1818
	 * Returns the <code>TypeFullnameCache</code> attribute.
1819
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1820
	 * @return The <code>TypeFullnameCache</code> attribute.
1821
	 * @see MethodMapper
1822
	 */
1823
	@SuppressWarnings("unused")
1824
	private static String getTypeFullnameCache(TaxonNameBase<?,?> taxonName) {
1825
		String result = null;
1826
		
1827
		try {
1828
		if (taxonName != null) {
1829
			Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
1830
			if (nameTypeDesignations.size() == 1) {
1831
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1832
				if (nameTypeDesignation != null) {
1833
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1834
					if (typeName != null) {
1835
						result = typeName.getTitleCache();
1836
					}
1837
				}
1838
			} else if (nameTypeDesignations.size() > 1) {
1839
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1840
			}
1841
		}
1842
		
1843
		} catch (Exception e) {
1844
			e.printStackTrace();
1845
		}
1846
		return result;
1847
	}
1848

    
1849
	
1850
	/**
1851
	 * Returns the <code>QualityStatusFk</code> attribute.
1852
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1853
	 * @return The <code>QualityStatusFk</code> attribute.
1854
	 * @see MethodMapper
1855
	 */
1856
	private static Integer getQualityStatusFk(TaxonNameBase taxonName) {
1857
		BitSet sources = getSources(taxonName);
1858
		return PesiTransformer.getQualityStatusKeyBySource(sources, taxonName);
1859
	}
1860

    
1861
	
1862
	/**
1863
	 * Returns the <code>QualityStatusCache</code> attribute.
1864
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1865
	 * @return The <code>QualityStatusCache</code> attribute.
1866
	 * @throws UndefinedTransformerMethodException 
1867
	 * @see MethodMapper
1868
	 */
1869
	@SuppressWarnings("unused")
1870
	private static String getQualityStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1871
		return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));
1872
	}
1873

    
1874
	
1875
	/**
1876
	 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1877
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1878
	 * @return The <code>TypeDesignationStatusFk</code> attribute.
1879
	 * @see MethodMapper
1880
	 */
1881
	@SuppressWarnings("unused")
1882
	private static Integer getTypeDesignationStatusFk(TaxonNameBase<?,?> taxonName) {
1883
		Integer result = null;
1884
		
1885
		try {
1886
		if (taxonName != null) {
1887
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1888
			if (typeDesignations.size() == 1) {
1889
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1890
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1891
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);
1892
			} else if (typeDesignations.size() > 1) {
1893
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1894
			}
1895
		}
1896
		
1897
		} catch (Exception e) {
1898
			e.printStackTrace();
1899
		}
1900
		return result;
1901
	}
1902

    
1903
	/**
1904
	 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1905
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1906
	 * @return The <code>TypeDesignationStatusCache</code> attribute.
1907
	 * @see MethodMapper
1908
	 */
1909
	@SuppressWarnings("unused")
1910
	private static String getTypeDesignationStatusCache(TaxonNameBase<?,?> taxonName) {
1911
		String result = null;
1912
		
1913
		try {
1914
		if (taxonName != null) {
1915
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1916
			if (typeDesignations.size() == 1) {
1917
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1918
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1919
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);
1920
			} else if (typeDesignations.size() > 1) {
1921
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1922
			}
1923
		}
1924
		
1925
		} catch (Exception e) {
1926
			e.printStackTrace();
1927
		}
1928
		return result;
1929
	}
1930
	
1931
	/**
1932
	 * Returns the <code>FossilStatusFk</code> attribute.
1933
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1934
	 * @return The <code>FossilStatusFk</code> attribute.
1935
	 * @see MethodMapper
1936
	 */
1937
	@SuppressWarnings("unused")
1938
	private static Integer getFossilStatusFk(IdentifiableEntity<?> identEntity, PesiExportState state) {
1939
		Integer result = null;
1940
		
1941
		Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
1942
		if (fossilStatuus.size() == 0){
1943
			return null;
1944
		}else if (fossilStatuus.size() > 1){
1945
			logger.warn("More than 1 fossil status given for " +  identEntity.getTitleCache() + " " + identEntity.getUuid());
1946
		}
1947
		String fossilStatus = fossilStatuus.iterator().next();
1948
		
1949
		int statusFk = state.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus);
1950
		return statusFk;
1951
	}
1952
	
1953
	/**
1954
	 * Returns the <code>FossilStatusCache</code> attribute.
1955
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1956
	 * @return The <code>FossilStatusCache</code> attribute.
1957
	 * @see MethodMapper
1958
	 */
1959
	@SuppressWarnings("unused")
1960
	private static String getFossilStatusCache(IdentifiableEntity<?> identEntity, PesiExportState state) {
1961
		String result = null;
1962
		Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
1963
		if (fossilStatuus.size() == 0){
1964
			return null;
1965
		}
1966
		for (String strFossilStatus : fossilStatuus){
1967
			result = CdmUtils.concat(";", result, strFossilStatus);
1968
		}
1969
		return result;
1970
	}
1971
	
1972
	/**
1973
	 * Returns the <code>IdInSource</code> attribute.
1974
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1975
	 * @return The <code>IdInSource</code> attribute.
1976
	 * @see MethodMapper
1977
	 */
1978
	@SuppressWarnings("unused")
1979
	private static String getIdInSource(IdentifiableEntity taxonName) {
1980
		String result = null;
1981
		
1982
		try {
1983
			Set<IdentifiableSource> sources = getPesiSources(taxonName);
1984
			if (sources.size() > 1){
1985
				logger.warn("There is > 1 Pesi source. This is not yet handled.");
1986
			}
1987
			if (sources.size() == 0){
1988
				logger.warn("There is no Pesi source!" +taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1989
			}
1990
			for (IdentifiableSource source : sources) {
1991
				Reference<?> ref = source.getCitation();
1992
				UUID refUuid = ref.getUuid();
1993
				String idInSource = source.getIdInSource();
1994
				if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
1995
					result = idInSource != null ? ("NameId: " + source.getIdInSource()) : null;
1996
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
1997
					result = idInSource != null ? ("TAX_ID: " + source.getIdInSource()) : null;
1998
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
1999
					result = idInSource != null ? ("tu_id: " + source.getIdInSource()) : null;
2000
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){  //Index Fungorum
2001
					result = idInSource != null ? ("if_id: " + source.getIdInSource()) : null;
2002
				}else{
2003
					if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
2004
				}
2005
				
2006
				String sourceIdNameSpace = source.getIdNamespace();
2007
				if (sourceIdNameSpace != null) {
2008
					if (sourceIdNameSpace.equals(PesiTransformer.STR_NAMESPACE_NOMINAL_TAXON)) {
2009
						result =  idInSource != null ? ("Nominal Taxon from TAX_ID: " + source.getIdInSource()):null;
2010
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_EPITHET_NAMESPACE)) {
2011
						result =  idInSource != null ? ("Inferred epithet from TAX_ID: " + source.getIdInSource()) : null;
2012
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_GENUS_NAMESPACE)) {
2013
						result =  idInSource != null ? ("Inferred genus from TAX_ID: " + source.getIdInSource()):null;
2014
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {
2015
						result =  idInSource != null ? ("Potential combination from TAX_ID: " + source.getIdInSource()):null;
2016
					} 
2017
				}
2018
				if (result == null) {
2019
					logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +", sourceIdNameSpace: " + source.getIdNamespace()+")");
2020
				}
2021
			}
2022
		} catch (Exception e) {
2023
			e.printStackTrace();
2024
			logger.error("An error occurs while creating idInSource..." + taxonName.getUuid() + " (" + taxonName.getTitleCache()+ e.getMessage());
2025
		}
2026

    
2027
		if (result == null) {
2028
			logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
2029
		}
2030
		return result;
2031
	}
2032
	
2033
	/**
2034
	 * Returns the idInSource for a given TaxonName only.
2035
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2036
	 * @return The idInSource.
2037
	 */
2038
	private static String getIdInSourceOnly(IdentifiableEntity identEntity) {
2039
		String result = null;
2040
		
2041
		// Get the sources first
2042
		Set<IdentifiableSource> sources = getPesiSources(identEntity);
2043

    
2044
		// Determine the idInSource
2045
		if (sources.size() == 1) {
2046
			IdentifiableSource source = sources.iterator().next();
2047
			if (source != null) {
2048
				result = source.getIdInSource();
2049
			}
2050
		} else if (sources.size() > 1) {
2051
			int count = 1;
2052
			result = "";
2053
			for (IdentifiableSource source : sources) {
2054
				result += source.getIdInSource();
2055
				if (count < sources.size()) {
2056
					result += "; ";
2057
				}
2058
				count++;
2059
			}
2060

    
2061
		}
2062
		
2063
		return result;
2064
	}
2065
	
2066
	/**
2067
	 * Returns the Sources for a given TaxonName only.
2068
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2069
	 * @return The Sources.
2070
	 */
2071
	private static Set<IdentifiableSource> getPesiSources(IdentifiableEntity identEntity) {
2072
		Set<IdentifiableSource> sources = new java.util.HashSet<IdentifiableSource>();
2073

    
2074
		//Taxon Names
2075
		if (identEntity.isInstanceOf(TaxonNameBase.class)){
2076
			// Sources from TaxonName
2077
			TaxonNameBase taxonName = CdmBase.deproxy(identEntity, TaxonNameBase.class);
2078
			Set<IdentifiableSource> testSources = identEntity.getSources();
2079
			sources = filterPesiSources(identEntity.getSources());
2080
			
2081
			if (sources.size() == 0 && testSources.size()>0){
2082
				IdentifiableSource source = testSources.iterator().next();
2083
				logger.warn("There are sources, but they are no pesi sources!!!" + source.getIdInSource() + " - " + source.getIdNamespace() + " - "+source.getCitation().generateTitle());
2084
			}
2085
			if (sources.size() > 1) {
2086
				logger.warn("This TaxonName has more than one Source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() + ")");
2087
			}
2088
			
2089
			// name has no PESI source, take sources from TaxonBase
2090
			if (sources == null || sources.isEmpty()) {
2091
				Set<TaxonBase> taxa = taxonName.getTaxonBases();
2092
				for (TaxonBase taxonBase: taxa){
2093
					sources.addAll(filterPesiSources(taxonBase.getSources()));
2094
				}
2095
			}
2096

    
2097
		//for TaxonBases
2098
		}else if (identEntity.isInstanceOf(TaxonBase.class)){
2099
			sources = filterPesiSources(identEntity.getSources());	
2100
		}
2101

    
2102
		/*TODO: deleted only for testing the inferred synonyms 
2103
		if (sources == null || sources.isEmpty()) {
2104
			logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2105
		}else if (sources.size() > 1){
2106
			logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2107
		}
2108
		*/
2109
		return sources;
2110
	}
2111
	
2112
	// return all sources with a PESI reference	
2113
	private static Set<IdentifiableSource> filterPesiSources(Set<? extends IdentifiableSource> sources) {
2114
		Set<IdentifiableSource> result = new HashSet<IdentifiableSource>();
2115
		for (IdentifiableSource source : sources){
2116
			Reference ref = source.getCitation();
2117
			UUID refUuid = ref.getUuid();
2118
			if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed) || 
2119
				refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)||
2120
				refUuid.equals(PesiTransformer.uuidSourceRefErms)||
2121
				refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum) ||
2122
				refUuid.equals(PesiTransformer.uuidSourceRefAuct)){
2123
				result.add(source);
2124
			}
2125
		}
2126
		return result;
2127
	}
2128

    
2129
	/**
2130
	 * Returns the <code>GUID</code> attribute.
2131
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2132
	 * @return The <code>GUID</code> attribute.
2133
	 * @see MethodMapper
2134
	 */
2135
	private static String getGUID(TaxonBase<?> taxon) {
2136
		if (taxon.getLsid() != null ){
2137
			return taxon.getLsid().getLsid();
2138
		}else if (taxon.hasMarker(PesiTransformer.uuidMarkerGuidIsMissing, true)){
2139
			return null;
2140
		}else{
2141
			return taxon.getUuid().toString();
2142
		}
2143
	}
2144
	
2145
	
2146
	
2147
	
2148
	/**
2149
	 * Returns the <code>DerivedFromGuid</code> attribute.
2150
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2151
	 * @return The <code>DerivedFromGuid</code> attribute.
2152
	 * @see MethodMapper
2153
	 */
2154
	@SuppressWarnings("unused")
2155
	private static String getDerivedFromGuid(TaxonBase<?> taxon) {
2156
		String result = null;
2157
		try {
2158
		// The same as GUID for now
2159
		result = getGUID(taxon);
2160
		} catch (Exception e) {
2161
			e.printStackTrace();
2162
		}
2163
		return result;
2164
	}
2165
	
2166
	/**
2167
	 * Returns the <code>CacheCitation</code> attribute.
2168
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2169
	 * @return The CacheCitation.
2170
	 * @see MethodMapper
2171
	 */
2172
	@SuppressWarnings("unused")
2173
	private static String getCacheCitation(TaxonBase taxon) {
2174
		// !!! See also doPhaseUpdates
2175
		
2176
		TaxonNameBase<?,?> taxonName = taxon.getName();
2177
		String result = "";
2178
		//TODO implement anew for taxa
2179
		try {
2180
			BitSet sources = getSources(taxonName);
2181
			if (sources.isEmpty()) {
2182
//				logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2183
			} else if (sources.get(PesiTransformer.SOURCE_ERMS)) {
2184
				// 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...
2185
				// 		 So the following code is some kind of harmless assumption.
2186
				Set<Extension> extensions = taxonName.getExtensions();
2187
				for (Extension extension : extensions) {
2188
					if (extension.getType().equals(cacheCitationExtensionType)) {
2189
						result = extension.getValue();
2190
					}
2191
				}
2192
			} else {
2193
				String expertName = getExpertName(taxon);
2194
				String webShowName = getWebShowName(taxonName);
2195
				
2196
				// idInSource only
2197
				String idInSource = getIdInSourceOnly(taxonName);
2198
				
2199
				// build the cacheCitation
2200
				if (expertName != null) {
2201
					result += expertName + ". ";
2202
				} else {
2203
					if (logger.isDebugEnabled()){logger.debug("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");}
2204
				}
2205
				if (webShowName != null) {
2206
					result += webShowName + ". ";
2207
				} else {
2208
					logger.warn("WebShowName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2209
				}
2210
				
2211
				if (getOriginalDB(taxonName).equals("FaEu")) {
2212
					result += "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
2213
				} else if (getOriginalDB(taxonName).equals("EM")) {
2214
					result += "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
2215
				}
2216
				
2217
				if (idInSource != null) {
2218
					result += idInSource;
2219
				} else {
2220
					logger.warn("IdInSource could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2221
				}
2222
			}
2223
		} catch (Exception e) {
2224
			e.printStackTrace();
2225
		}
2226
		
2227
		if (StringUtils.isBlank(result)) {
2228
			return null;
2229
		} else {
2230
			return result;
2231
		}
2232
	}
2233
	
2234
	/**
2235
	 * Returns the <code>OriginalDB</code> attribute.
2236
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2237
	 * @return The <code>OriginalDB</code> attribute.
2238
	 * @see MethodMapper
2239
	 */
2240
	private static String getOriginalDB(IdentifiableEntity identEntity) {
2241
		// Sources from TaxonName
2242
		BitSet sources  = getSources(identEntity);
2243
		return PesiTransformer.getOriginalDbBySources(sources);
2244
	}
2245
	
2246
	/**
2247
	 * Returns the <code>LastAction</code> attribute.
2248
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2249
	 * @return The <code>LastAction</code> attribute.
2250
	 * @see MethodMapper
2251
	 */
2252
	@SuppressWarnings("unused")
2253
	private static String getLastAction(IdentifiableEntity<?> identEntity) {
2254
		String result = null;
2255
		try {
2256
		Set<Extension> extensions = identEntity.getExtensions();
2257
		for (Extension extension : extensions) {
2258
			if (extension.getType().equals(lastActionExtensionType)) {
2259
				result = extension.getValue();
2260
			}
2261
		}
2262
		} catch (Exception e) {
2263
			e.printStackTrace();
2264
		}
2265
		return result;
2266
	}
2267
	
2268
	/**
2269
	 * Returns the <code>LastActionDate</code> attribute.
2270
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2271
	 * @return The <code>LastActionDate</code> attribute.
2272
	 * @see MethodMapper
2273
	 */
2274
	@SuppressWarnings({ "unused" })
2275
	private static DateTime getLastActionDate(IdentifiableEntity identEntity) {
2276
		DateTime result = null;
2277
		try {
2278
			Set<Extension> extensions = identEntity.getExtensions();
2279
			for (Extension extension : extensions) {
2280
				if (extension.getType().equals(lastActionDateExtensionType)) {
2281
					String dateTime = extension.getValue();
2282
					if (dateTime != null) {
2283
						DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S");
2284
						result = formatter.parseDateTime(dateTime);
2285
					}
2286
				}
2287
			}
2288
		} catch (Exception e) {
2289
			e.printStackTrace();
2290
		}
2291
		return result;
2292
	}
2293
	
2294
	/**
2295
	 * Returns the <code>ExpertName</code> attribute.
2296
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2297
	 * @return The <code>ExpertName</code> attribute.
2298
	 * @see MethodMapper
2299
	 */
2300
	@SuppressWarnings("unused")
2301
	private static String getExpertName(TaxonBase<?> taxonName) {
2302
		String result = null;
2303
		try {
2304
		Set<Extension> extensions = taxonName.getExtensions();
2305
		for (Extension extension : extensions) {
2306
			if (extension.getType().equals(expertNameExtensionType)) {
2307
				result = extension.getValue();
2308
			}
2309
		}
2310
		} catch (Exception e) {
2311
			e.printStackTrace();
2312
		}
2313
		return result;
2314
	}
2315
	
2316
	/**
2317
	 * Returns the <code>ExpertFk</code> attribute.
2318
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2319
	 * @param state The {@link PesiExportState PesiExportState}.
2320
	 * @return The <code>ExpertFk</code> attribute.
2321
	 * @see MethodMapper
2322
	 */
2323
	private static Integer getExpertFk(Reference<?> reference, PesiExportState state) {
2324
		Integer result = state.getDbId(reference);
2325
		return result;
2326
	}
2327
	
2328
	/**
2329
	 * Returns the <code>SpeciesExpertName</code> attribute.
2330
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2331
	 * @return The <code>SpeciesExpertName</code> attribute.
2332
	 * @see MethodMapper
2333
	 */
2334
	@SuppressWarnings("unused")
2335
	private static String getSpeciesExpertName(TaxonBase<?> taxonName) {
2336
		String result = null;
2337
		try {
2338
		Set<Extension> extensions = taxonName.getExtensions();
2339
		for (Extension extension : extensions) {
2340
			if (extension.getType().equals(speciesExpertNameExtensionType)) {
2341
				result = extension.getValue();
2342
			}
2343
		}
2344
		} catch (Exception e) {
2345
			e.printStackTrace();
2346
		}
2347
		return result;
2348
	}
2349
	
2350
	/**
2351
	 * Returns the <code>SpeciesExpertFk</code> attribute.
2352
	 * @param reference The {@link Reference Reference}.
2353
	 * @param state The {@link PesiExportState PesiExportState}.
2354
	 * @return The <code>SpeciesExpertFk</code> attribute.
2355
	 * @see MethodMapper
2356
	 */
2357
	private static Integer getSpeciesExpertFk(Reference<?> reference, PesiExportState state) {
2358
		Integer result = state.getDbId(reference);
2359
		return result;
2360
	}
2361
	
2362
	
2363
	/**
2364
	 * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
2365
	 * Identifiable Entity as a BitSet
2366
	 * @param identEntity
2367
	 * @return
2368
	 */
2369
	private static BitSet getSources(IdentifiableEntity<?> identEntity){
2370
		BitSet bitSet = new BitSet();
2371
		Set<IdentifiableSource> sources = getPesiSources(identEntity);
2372
		for (IdentifiableSource source : sources) {
2373
			Reference<?> ref = source.getCitation();
2374
			UUID refUuid = ref.getUuid();
2375
			if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
2376
				bitSet.set(PesiTransformer.SOURCE_EM);
2377
			}else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
2378
				bitSet.set(PesiTransformer.SOURCE_FE);
2379
			}else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
2380
				bitSet.set(PesiTransformer.SOURCE_ERMS);
2381
			}else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){
2382
				bitSet.set(PesiTransformer.SOURCE_IF);
2383
			}else{
2384
				if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
2385
			}
2386
		}
2387
		return bitSet;
2388
		
2389
	}
2390
	
2391
	protected static NonViralNameDefaultCacheStrategy getCacheStrategy(TaxonNameBase<?, ?> taxonName) {
2392
		taxonName = CdmBase.deproxy(taxonName, TaxonNameBase.class);
2393
		NonViralNameDefaultCacheStrategy<?> cacheStrategy;
2394
		if (taxonName.isInstanceOf(ZoologicalName.class)){
2395
			cacheStrategy = zooNameStrategy;
2396
		}else if (taxonName.isInstanceOf(BotanicalName.class)) {
2397
			cacheStrategy = botanicalNameStrategy;
2398
		}else if (taxonName.getClass().equals(NonViralName.class)) {
2399
			cacheStrategy = nonViralNameStrategy;
2400
		}else if (taxonName.getClass().equals(BacterialName.class)) {
2401
			cacheStrategy = bacterialNameStrategy;
2402
		}else{
2403
			logger.error("Unhandled taxon name type. Can't define strategy class");
2404
			cacheStrategy = botanicalNameStrategy;
2405
		}
2406
		return cacheStrategy;
2407
	}
2408
	
2409
	/**
2410
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
2411
	 * @param relationship The {@link RelationshipBase Relationship}.
2412
	 * @param state The {@link PesiExportState PesiExportState}.
2413
	 * @return The <code>TaxonFk1</code> attribute.
2414
	 * @see MethodMapper
2415
	 */
2416
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
2417
		
2418
		return getObjectFk(relationship, state, true);
2419
	}
2420
	
2421
	/**
2422
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
2423
	 * @param relationship The {@link RelationshipBase Relationship}.
2424
	 * @param state The {@link PesiExportState PesiExportState}.
2425
	 * @return The <code>TaxonFk2</code> attribute.
2426
	 * @see MethodMapper
2427
	 */
2428
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
2429
		return getObjectFk(relationship, state, false);
2430
	}
2431
	
2432
	/**
2433
	 * Returns the database key of an object in the given relationship.
2434
	 * @param relationship {@link RelationshipBase RelationshipBase}.
2435
	 * @param state {@link PesiExportState PesiExportState}.
2436
	 * @param isFrom A boolean value indicating whether the database key of the parent or child in this relationship is searched. <code>true</code> means the child is searched. <code>false</code> means the parent is searched.
2437
	 * @return The database key of an object in the given relationship.
2438
	 */
2439
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
2440
		TaxonBase<?> taxonBase = null;
2441
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
2442
			TaxonRelationship tr = (TaxonRelationship)relationship;
2443
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
2444
		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
2445
			SynonymRelationship sr = (SynonymRelationship)relationship;
2446
			taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
2447
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
2448
			if (isFrom){
2449
				return state.getDbId(state.getCurrentFromObject());
2450
			}else{
2451
				return state.getDbId(state.getCurrentToObject());
2452
			}
2453
		}
2454
		if (taxonBase != null) {
2455
			if (! isPesiTaxon(taxonBase)){
2456
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
2457
				return null;
2458
			}else{
2459
				return state.getDbId(taxonBase);	
2460
			}
2461
			
2462
		}
2463
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
2464
		return null;
2465
	}
2466
	
2467
	/**
2468
	 * Returns the <code>RelQualifierCache</code> attribute.
2469
	 * @param relationship The {@link RelationshipBase Relationship}.
2470
	 * @return The <code>RelQualifierCache</code> attribute.
2471
	 * @see MethodMapper
2472
	 */
2473
	@SuppressWarnings("unused")
2474
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
2475
		String result = null;
2476
		NomenclaturalCode code = null;
2477
		if (relationship.isInstanceOf(TaxonRelationship.class)){
2478
			code = CdmBase.deproxy(relationship, TaxonRelationship.class).getToTaxon().getName().getNomenclaturalCode();
2479
		}else if (relationship.isInstanceOf(SynonymRelationship.class)){
2480
			code = CdmBase.deproxy(relationship, SynonymRelationship.class).getAcceptedTaxon().getName().getNomenclaturalCode();
2481
		}else if (relationship.isInstanceOf(NameRelationship.class)){
2482
			code = CdmBase.deproxy(relationship,  NameRelationship.class).getFromName().getNomenclaturalCode();
2483
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
2484
			code = CdmBase.deproxy(relationship,  HybridRelationship.class).getParentName().getNomenclaturalCode();
2485
		}
2486
		if (code != null) {
2487
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
2488
		} else {
2489
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
2490
		}
2491
		return result;
2492
	}
2493
	
2494
	/**
2495
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
2496
	 * @param relationship The {@link RelationshipBase Relationship}.
2497
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
2498
	 * @see MethodMapper
2499
	 */
2500
	@SuppressWarnings("unused")
2501
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
2502
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
2503
	}
2504
	/**
2505
	 * Returns the <code>Notes</code> attribute.
2506
	 * @param relationship The {@link RelationshipBase Relationship}.
2507
	 * @return The <code>Notes</code> attribute.
2508
	 * @see MethodMapper
2509
	 */
2510
	@SuppressWarnings("unused")
2511
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
2512
		// TODO
2513
		return null;
2514
	}
2515

    
2516
	
2517
	/**
2518
	 * Returns the CDM to PESI specific export mappings.
2519
	 * @return The {@link PesiExportMapping PesiExportMapping}.
2520
	 */
2521
	private PesiExportMapping getMapping() {
2522
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2523
		
2524
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2525
		mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2526
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2527
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
2528
		
2529
		mapping.addMapper(MethodMapper.NewInstance("GUID", this));
2530
		
2531
		mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));
2532
		mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));
2533
		mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently
2534
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));
2535
		
2536
		// DisplayName
2537
		mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));
2538

    
2539
		// FossilStatus (Fk, Cache)
2540
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, IdentifiableEntity.class, PesiExportState.class));
2541
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, IdentifiableEntity.class, PesiExportState.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2542
		
2543
		//handled by name mapping
2544
		mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2545
		mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2546
		
2547
		//experts
2548
		ExtensionType extensionTypeSpeciesExpertName = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
2549
		mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));
2550
		ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
2551
		mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));
2552
		
2553
//		mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class));  //by AM, doesn't work, FK exception
2554
		mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2555
		
2556
		addNameMappers(mapping);
2557

    
2558
		return mapping;
2559
	}
2560
	
2561
	/**
2562
	 * Returns the CDM to PESI specific export mappings.
2563
	 * @param state 
2564
	 * @return The {@link PesiExportMapping PesiExportMapping}.
2565
	 * @throws UndefinedTransformerMethodException 
2566
	 */
2567
	private PesiExportMapping getPureNameMapping(PesiExportState state) throws UndefinedTransformerMethodException {
2568
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2569
		
2570
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2571

    
2572
		//		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2573

    
2574
		mapping.addMapper(MethodMapper.NewInstance("KingdomFk", this, TaxonNameBase.class));
2575
		mapping.addMapper(MethodMapper.NewInstance("RankFk", this, TaxonNameBase.class));
2576
		mapping.addMapper(MethodMapper.NewInstance("RankCache", this, TaxonNameBase.class, PesiExportState.class));
2577
		mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER , PesiTransformer.T_STATUS_UNACCEPTED));
2578
		mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR , state.getTransformer().getTaxonStatusCacheByKey( PesiTransformer.T_STATUS_UNACCEPTED)));
2579
		mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));  
2580
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));
2581
		
2582
		// DisplayName
2583
		mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));
2584
		
2585
		mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2586
		mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2587
		
2588
		addNameMappers(mapping);
2589
		//TODO add author mapper, TypeNameFk
2590

    
2591
		return mapping;
2592
	}
2593

    
2594
	private void addNameMappers(PesiExportMapping mapping) {
2595
		mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2596
		mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2597
		mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));
2598
		mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2599
		
2600
//		mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName"));  //does not work as we need other cache strategy
2601
		mapping.addMapper(MethodMapper.NewInstance("WebSearchName", this, TaxonNameBase.class));
2602
		
2603
//		mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName"));    //does not work as we need other cache strategy
2604
		mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonNameBase.class));
2605
		
2606
		
2607
		mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonNameBase.class));
2608
		
2609
		mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));
2610
		mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2611
		mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonNameBase.class));
2612
		//TODO TypeNameFk
2613
		
2614
		//quality status
2615
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonNameBase.class));
2616
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2617
		
2618
		mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));
2619
		mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );
2620

    
2621
		//mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2622

    
2623
	}
2624
	
2625
	private PesiExportMapping getSynRelMapping() {
2626
		PesiExportMapping mapping = new PesiExportMapping(dbTableNameSynRel);
2627
		
2628
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase.class, PesiExportState.class));
2629
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase.class, PesiExportState.class));
2630
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this,  RelationshipBase.class));
2631
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
2632
		mapping.addMapper(MethodMapper.NewInstance("Notes", this,  RelationshipBase.class));
2633

    
2634
		return mapping;
2635
	}
2636

    
2637
	private PesiExportMapping getAdditionalSourceMapping(PesiExportState state)  throws UndefinedTransformerMethodException{
2638
		PesiExportMapping mapping = new PesiExportMapping(dbTableAdditionalSourceRel);
2639
		
2640
		mapping.addMapper(IdMapper.NewInstance("TaxonFk"));
2641
		mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2642
		
2643
		mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceFk"));
2644
		mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE));
2645

    
2646
		//we have only nomenclatural references here
2647
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER , PesiTransformer.NOMENCLATURAL_REFERENCE));
2648
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, state.getTransformer().getSourceUseCacheByKey( PesiTransformer.NOMENCLATURAL_REFERENCE)));
2649
		
2650
		mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "SourceDetail"));
2651
		
2652
		return mapping;
2653
	}
2654

    
2655
}
(11-11/12)