Project

General

Profile

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

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

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

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

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

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

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

    
210
			//"PHASE 1b: Handle names without taxa ...
211
			success &= doNames(state);
212

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

    
229
			if (!success){
230
				state.setUnsuccessfull();
231
			}
232
			return;
233
		} catch (SQLException e) {
234
			e.printStackTrace();
235
			logger.error(e.getMessage());
236
			state.setUnsuccessfull();
237
			return;
238
		}
239
	}
240

    
241
	
242

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

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

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

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

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

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

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

    
330
				
331
				
332
			}
333
			
334

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

    
364

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

    
424
	
425
	
426
	// 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
427
	private boolean doPhase02(PesiExportState state) {
428
		int count = 0;
429
		int pastCount = 0;
430
		List<Taxon> list;
431
		boolean success = true;
432
		// Get the limit for objects to save within a single transaction.
433
		int limit = state.getConfig().getLimitSave();
434

    
435
		
436
		logger.info("PHASE 2: Make ParentFk and TreeIndex ... limit is " + limit);
437
		// Start transaction
438
		TransactionStatus txStatus = startTransaction(true);
439
		int partitionCount = 0;
440

    
441
//		ProfilerController.memorySnapshot();
442
		while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, null)) != null   ) {
443
			
444
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
445
			for (Taxon taxon : list) {
446
				for (TaxonNode node : taxon.getTaxonNodes()){
447
					doCount(count++, modCount, pluralString);
448
					TaxonNode parentNode = node.getParent();
449
					if (parentNode != null){
450
						int childId = state.getDbId( taxon); 
451
						int parentId = state.getDbId(parentNode.getTaxon());
452
						success &= invokeParentTaxonFk(parentId, childId);
453
					}
454
				}
455
				
456
			}
457
			
458
			// Commit transaction
459
			commitTransaction(txStatus);
460
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
461
			pastCount = count;
462
			// Start transaction
463
			txStatus = startTransaction(true);
464
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
465
			
466
		}
467
		if (list == null ) {
468
			logger.info("No " + pluralString + " left to fetch.");
469
		}
470
		
471
		// Commit transaction
472
		commitTransaction(txStatus);
473
		
474
		return success;
475
		
476
	}
477
	
478
	// 4th round: Add TreeIndex to each taxon
479
	private boolean doPhase04(PesiExportState state) {
480
		boolean success = true;
481
		
482
		logger.info("PHASE 2: Make TreeIndex ... ");
483
	
484
		state.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
485
		
486
		return success;
487
		
488
	}
489
	
490
	
491
	// 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
492
	private boolean doPhase02_OLD(PesiExportState state) {
493
		boolean success = true;
494
		if (! state.getConfig().isDoTreeIndex()){
495
			logger.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
496
			return success;
497
		}
498
		
499
		List<Classification> classificationList = null;
500
		logger.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
501
		
502
		// Specify starting ranks for tree traversing
503
		rankList.add(Rank.KINGDOM());
504
		rankList.add(Rank.GENUS());
505

    
506
		// Specify where to stop traversing (value) when starting at a specific Rank (key)
507
		rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
508
		rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
509
		
510
		StringBuffer treeIndex = new StringBuffer();
511
		
512
		// Retrieve list of classifications
513
		TransactionStatus txStatus = startTransaction(true);
514
		logger.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
515
		classificationList = getClassificationService().listClassifications(null, 0, null, null);
516
		commitTransaction(txStatus);
517
		logger.debug("Committed transaction.");
518

    
519
		logger.info("Fetched " + classificationList.size() + " classification(s).");
520

    
521
		setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex, "TreeIndex", "TreeIndex", "TI"));
522
		List<TaxonNode> rankSpecificRootNodes;
523
		for (Classification classification : classificationList) {
524
			for (Rank rank : rankList) {
525
				
526
				txStatus = startTransaction(true);
527
				logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
528

    
529
				rankSpecificRootNodes = getClassificationService().loadRankSpecificRootNodes(classification, rank, null);
530
				logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
531

    
532
				commitTransaction(txStatus);
533
				logger.debug("Committed transaction.");
534

    
535
				for (TaxonNode rootNode : rankSpecificRootNodes) {
536
					txStatus = startTransaction(false);
537
					Rank endRank = rank2endRankMap.get(rank);
538
					if (endRank != null) {
539
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");
540
					} else {
541
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");
542
					}
543

    
544
					TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
545

    
546
					if (isPesiTaxon(newNode.getTaxon())){
547
						TaxonNode parentNode = newNode.getParent();
548
						if (rank.equals(Rank.KINGDOM())) {
549
							treeIndex = new StringBuffer();
550
							treeIndex.append("#");
551
						} else {
552
							// Get treeIndex from parentNode
553
							if (parentNode != null) {
554
								boolean annotationFound = false;
555
								Set<Annotation> annotations = parentNode.getAnnotations();
556
								for (Annotation annotation : annotations) {
557
									AnnotationType annotationType = annotation.getAnnotationType();
558
									if (annotationType != null && annotationType.equals(getTreeIndexAnnotationType())) {
559
										treeIndex = new StringBuffer(CdmUtils.Nz(annotation.getText()));
560
										annotationFound = true;
561
	//									logger.error("treeIndex: " + treeIndex);
562
										break;
563
									}
564
								}
565
								if (!annotationFound) {
566
									// This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
567
									logger.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode.getUuid() + ", Taxon: " + parentNode.getTaxon().getUuid());
568
									treeIndex = new StringBuffer();
569
									treeIndex.append("#");
570
								}
571
							} else {
572
								// TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
573
								logger.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode.getUuid());
574
								treeIndex = new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
575
								treeIndex.append("#");
576
							}
577
						}
578
						nomenclaturalCode = newNode.getTaxon().getName().getNomenclaturalCode();
579
						kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
580
						traverseTree(newNode, parentNode, treeIndex, endRank, state);
581
						parentNode =null;
582
					}else{
583
						logger.debug("Taxon is not a PESI taxon: " + newNode.getTaxon().getUuid());
584
					}
585
					
586
					newNode = null;
587
					
588
					try {
589
						commitTransaction(txStatus);
590
						logger.debug("Committed transaction.");
591
					} catch (Exception e) {
592
						logger.error(e.getMessage());
593
						e.printStackTrace();
594
					}
595

    
596
				}
597
				rankSpecificRootNodes = null;
598
			}
599
			
600
		}
601
		
602
		logger.warn("Taking snapshot at the end of phase 2 of taxonExport");
603
		ProfilerController.memorySnapshot();
604
		return success;
605
	}	
606

    
607
	//PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
608
	private boolean doPhase03(PesiExportState state) {
609
		int count = 0;
610
		int pastCount = 0;
611
		boolean success = true;
612
		if (! state.getConfig().isDoTreeIndex()){
613
			logger.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
614
			return success;
615
		}
616
		// Get the limit for objects to save within a single transaction.
617
		int limit = state.getConfig().getLimitSave();
618

    
619
		List<TaxonBase> list;
620
		logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
621
		// Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
622
		
623
		// Start transaction
624
		TransactionStatus txStatus = startTransaction(true);
625
		logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
626
		int partitionCount = 0;
627
		while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {
628

    
629
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
630
			for (TaxonBase<?> taxon : list) {
631
				TaxonNameBase<?,?> taxonName = taxon.getName();
632
				// Determine expertFk
633
//				Integer expertFk = makeExpertFk(state, taxonName);
634
//
635
//				// Determine speciesExpertFk
636
//				Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
637

    
638
				doCount(count++, modCount, pluralString);
639
				Integer typeNameFk = getTypeNameFk(taxonName, state);
640
				
641
				//TODO why are expertFks needed? (Andreas M.)
642
//				if (expertFk != null || speciesExpertFk != null) {
643
					invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon), 
644
							typeNameFk, kingdomFk);
645
//				}
646
					
647
					taxon = null;
648
					taxonName = null;
649
			}
650

    
651
			// Commit transaction
652
			commitTransaction(txStatus);
653
			logger.debug("Committed transaction.");
654
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
655
			pastCount = count;
656

    
657
			// Start transaction
658
			txStatus = startTransaction(true);
659
			logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
660
		}
661
		if (list == null) {
662
			logger.info("No " + pluralString + " left to fetch.");
663
		}
664
		
665
		list = null;
666
		
667
		// Commit transaction
668
		commitTransaction(txStatus);
669
		
670
		logger.debug("Committed transaction.");
671
		logger.warn("Taking snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount);
672
		ProfilerController.memorySnapshot();
673
		return success;
674
	}
675
	
676
	//	"PHASE 4: Creating Inferred Synonyms..."
677
	private boolean doPhase05(PesiExportState state, PesiExportMapping mapping, PesiExportMapping synRelMapping) throws SQLException {
678
		int count;
679
		int pastCount;
680
		boolean success = true;
681
		// Get the limit for objects to save within a single transaction.
682
		if (! state.getConfig().isDoInferredSynonyms()){
683
			logger.info ("Ignore PHASE 4: Creating Inferred Synonyms...");
684
			return success;
685
		}
686
		
687
		int limit = state.getConfig().getLimitSave();
688
		// Create inferred synonyms for accepted taxa
689
		logger.info("PHASE 4: Creating Inferred Synonyms...");
690

    
691
		// Determine the count of elements in datawarehouse database table Taxon
692
		currentTaxonId = determineTaxonCount(state);
693
		currentTaxonId++;
694

    
695
		count = 0;
696
		pastCount = 0;
697
		int pageSize = limit;
698
		int pageNumber = 1;
699
		String inferredSynonymPluralString = "Inferred Synonyms";
700
		
701
		// Start transaction
702
		TransactionStatus txStatus = startTransaction(true);
703
		logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
704
		List<TaxonBase> taxonList = null;
705
		
706
		
707
		
708
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SPECIES(), pageSize, pageNumber)).size() > 0) {
709
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
710

    
711
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
712
			inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
713
					synRelMapping, taxonList));
714
			
715
			doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
716
			// Commit transaction
717
			commitTransaction(txStatus);
718
			logger.debug("Committed transaction.");
719
			logger.info("Exported " + (taxonList.size()) + " " + inferredSynonymPluralString + ". Total: " + count);
720
			//pastCount = count;
721
			
722
			// Save Rank Data and KingdomFk for inferred synonyms
723
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
724
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk);
725
			}
726

    
727
			// Start transaction
728
			txStatus = startTransaction(true);
729
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
730
			
731
			// Increment pageNumber
732
			pageNumber++;
733
		}
734
		
735
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", Rank.SUBSPECIES(), pageSize, pageNumber)).size() > 0) {
736
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
737

    
738
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
739
			inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
740
					synRelMapping, taxonList));
741
			;
742
			doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
743
			// Commit transaction
744
			commitTransaction(txStatus);
745
			logger.debug("Committed transaction.");
746
			logger.info("Exported " + taxonList.size()+ " " + inferredSynonymPluralString + ". Total: " + count);
747
			//pastCount = count;
748
			
749
			// Save Rank Data and KingdomFk for inferred synonyms
750
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
751
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk);
752
			}
753

    
754
			// Start transaction
755
			txStatus = startTransaction(true);
756
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
757
			
758
			// Increment pageNumber
759
			pageNumber++;
760
		}
761
		if (taxonList.size() == 0) {
762
			logger.info("No " + parentPluralString + " left to fetch.");
763
		}
764
		
765
		taxonList = null;
766
		logger.warn("Taking snapshot at the end of phase 4 of taxonExport");
767
		ProfilerController.memorySnapshot();
768
		
769
		// Commit transaction
770
		commitTransaction(txStatus);
771
		logger.warn("Taking snapshot at the end of phase 4 after commit of taxonExport");
772
		ProfilerController.memorySnapshot();
773
		System.gc();
774
		logger.warn("Taking snapshot at the end of phase 4 after gc() of taxonExport");
775
		ProfilerController.memorySnapshot();
776
		logger.debug("Committed transaction.");
777
		return success;
778
	}
779

    
780
	/**
781
	 * @param state
782
	 * @param mapping
783
	 * @param synRelMapping
784
	 * @param currentTaxonId
785
	 * @param taxonList
786
	 * @param inferredSynonymsDataToBeSaved
787
	 * @return
788
	 */
789
	private HashMap<Integer, TaxonNameBase<?, ?>> createInferredSynonymsForTaxonList(PesiExportState state,
790
			PesiExportMapping mapping, PesiExportMapping synRelMapping,	 List<TaxonBase> taxonList) {
791
		
792
		Taxon acceptedTaxon;
793
		Classification classification = null;
794
		List<Synonym> inferredSynonyms = null;
795
		boolean localSuccess = true;
796
		
797
		HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
798
		
799
		for (TaxonBase<?> taxonBase : taxonList) {
800
		
801
			if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
802
				acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
803
				TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
804
				
805
				if (taxonName.isInstanceOf(ZoologicalName.class)) {
806
					nomenclaturalCode  = taxonName.getNomenclaturalCode();
807
					kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
808

    
809
					Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();
810
					TaxonNode singleNode = null;
811
					
812
					if (taxonNodes.size() > 0) {
813
						// Determine the classification of the current TaxonNode
814
						
815
						singleNode = taxonNodes.iterator().next();
816
						if (singleNode != null) {
817
							classification = singleNode.getClassification();
818
						} else {
819
							logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");
820
						}
821
					} else {
822
						// Classification could not be determined directly from this TaxonNode
823
						// The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
824
						if (taxonNodes.size() == 0) {
825
							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");
826
						
827
						}
828
					}
829
					
830
					if (classification != null) {
831
						try{
832
							TaxonNameBase name = acceptedTaxon.getName();
833
							//if (name.isSpecies() || name.isInfraSpecific()){
834
								inferredSynonyms  = getTaxonService().createAllInferredSynonyms(acceptedTaxon, classification, true);
835
							//}
836
//								inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
837
							if (inferredSynonyms != null) {
838
								for (Synonym synonym : inferredSynonyms) {
839
//									TaxonNameBase<?,?> synonymName = synonym.getName();
840
									MarkerType markerType =getUuidMarkerType(PesiTransformer.uuidMarkerGuidIsMissing, state);
841
									synonym.addMarker(Marker.NewInstance(markerType, true));
842
									// Both Synonym and its TaxonName have no valid Id yet
843
									synonym.setId(currentTaxonId++);
844
									
845
									
846
									localSuccess &= mapping.invoke(synonym);
847
									//get SynonymRelationship and export
848
									if (synonym.getSynonymRelations().isEmpty() ){
849
										SynonymRelationship synRel;					
850
										IdentifiableSource source = synonym.getSources().iterator().next();
851
										if (source.getIdNamespace().contains("Potential combination")){
852
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.POTENTIAL_COMBINATION_OF());
853
											logger.warn(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to potential combination");
854
										} else if (source.getIdNamespace().contains("Inferred Genus")){
855
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_GENUS_OF());
856
											logger.warn(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred genus");
857
										} else if (source.getIdNamespace().contains("Inferred Epithet")){
858
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_EPITHET_OF());
859
											logger.warn(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred epithet");
860
										} else{
861
											synRel = acceptedTaxon.addSynonym(synonym, SynonymRelationshipType.INFERRED_SYNONYM_OF());
862
											logger.warn(synonym.getTitleCache() + " has no synonym relationship to " + acceptedTaxon.getTitleCache() + " type is set to inferred synonym");
863
										}
864
										
865
										localSuccess &= synRelMapping.invoke(synRel);
866
										if (!localSuccess) {
867
											logger.warn("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
868
										}
869
										synRel = null;
870
									} else {
871
										for (SynonymRelationship synRel: synonym.getSynonymRelations()){
872
											localSuccess &= synRelMapping.invoke(synRel);
873
											if (!localSuccess) {
874
												logger.warn("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
875
											}
876
											synRel = null;
877
										}
878
									}
879
									
880
									inferredSynonymsDataToBeSaved.put(synonym.getId(), synonym.getName());
881
								}
882
							}
883
						}catch(Exception e){
884
							logger.error(e.getMessage());
885
							e.printStackTrace();
886
						}
887
					} else {
888
						logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");
889
					}
890
				} else {
891
//							logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
892
				}
893
			} else {
894
				logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");
895
			}
896
		}
897
		return inferredSynonymsDataToBeSaved;
898
	}
899
	
900

    
901
	/**
902
	 * Handles names that do not appear in taxa
903
	 * @param state
904
	 * @param mapping
905
	 * @return
906
	 */
907
	private boolean doNames(PesiExportState state)  throws SQLException {
908
		
909
		boolean success = true;
910
		if (! state.getConfig().isDoPureNames()){
911
			logger.info ("Ignore PHASE 1b: PureNames");
912
			return success;
913
		}
914
		
915
		try {
916
			PesiExportMapping mapping = getPureNameMapping(state);
917
			mapping.initialize(state);
918
			int count = 0;
919
			int pastCount = 0;
920
			List<NonViralName<?>> list;
921
			success = true;
922
			// Get the limit for objects to save within a single transaction.
923
			int limit = state.getConfig().getLimitSave();
924

    
925
			
926
			logger.info("PHASE 1b: Export Pure Names ...");
927
			// Start transaction
928
			TransactionStatus txStatus = startTransaction(true);
929
			logger.info("Started new transaction for Pure Names. Fetching some " + pluralString + " (max: " + limit + ") ...");
930
			
931
			int partitionCount = 0;
932
			while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {
933

    
934
				logger.info("Fetched " + list.size() + " names without taxa. Exporting...");
935
				for (TaxonNameBase<?,?> taxonName : list) {
936
					doCount(count++, modCount, pluralString);
937
					success &= mapping.invoke(taxonName);
938
				}
939

    
940
				// Commit transaction
941
				commitTransaction(txStatus);
942
				logger.debug("Committed transaction.");
943
				logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
944
				pastCount = count;
945

    
946
				// Start transaction
947
				txStatus = startTransaction(true);
948
				logger.info("Started new transaction for PureNames. Fetching some " + pluralString + " (max: " + limit + ") ...");
949
			}
950
			if (list == null) {
951
				logger.info("No " + pluralString + " left to fetch.");
952
			}
953
			// Commit transaction
954
			commitTransaction(txStatus);
955
			logger.debug("Committed transaction.");
956
		} catch (Exception e) {
957
			logger.error("Error occurred in pure name export");
958
			e.printStackTrace();
959
			success = false;
960
		}
961
		return success;
962
	}
963

    
964
	/**
965
	 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
966
	 * @param state The {@link PesiExportState PesiExportState}.
967
	 * @return The count.
968
	 */
969
	private Integer determineTaxonCount(PesiExportState state) {
970
		Integer result = null;
971
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
972
		
973
		String sql;
974
		Source destination =  pesiConfig.getDestination();
975
		sql = "SELECT max(taxonId) FROM Taxon";
976
		destination.setQuery(sql);
977
		ResultSet resultSet = destination.getResultSet();
978
		try {
979
			resultSet.next();
980
			result = resultSet.getInt(1);
981
		} catch (SQLException e) {
982
			logger.error("TaxonCount could not be determined: " + e.getMessage());
983
			e.printStackTrace();
984
		}
985
		return result;
986
	}
987
	
988
	/**
989
	 * Checks whether a parent at specific level has a specific Rank.
990
	 * @param taxonName A {@link TaxonNameBase TaxonName}.
991
	 * @param level The ancestor level.
992
	 * @param ancestorRank The ancestor rank.
993
	 * @return Whether a parent at a specific level has a specific Rank.
994
	 */
995
	private boolean validateAncestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {
996
		boolean result = false;
997
		TaxonNode parentNode = null;
998
		if (taxonBase.isInstanceOf(Taxon.class)){
999
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1000
			// Get ancestor Taxon via TaxonNode
1001
			Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
1002
			if (taxonNodes.size() == 1) {
1003
				TaxonNode taxonNode = taxonNodes.iterator().next();
1004
				if (taxonNode != null) {
1005
					for (int i = 0; i < level; i++) {
1006
						if (taxonNode != null) {
1007
							taxonNode  = taxonNode.getParent();
1008
						}
1009
					}
1010
					parentNode = taxonNode;
1011
				}
1012
			} else if (taxonNodes.size() > 1) {
1013
				logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1014
			}
1015
		}
1016
		//compare
1017
		if (parentNode != null) {
1018
			TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);
1019
			Taxon parentTaxon = node.getTaxon();
1020
			if (parentTaxon != null) {
1021
				TaxonNameBase<?,?> parentTaxonName = parentTaxon.getName();
1022
				if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {
1023
					result = true;
1024
				}
1025
			} else {
1026
				logger.error("This TaxonNode has no Taxon: " + node.getUuid());
1027
			}
1028
		}
1029
		return result;
1030
	}
1031

    
1032
	/**
1033
	 * Returns the AnnotationType for a given UUID.
1034
	 * @param uuid The Annotation UUID.
1035
	 * @param label The Annotation label.
1036
	 * @param text The Annotation text.
1037
	 * @param labelAbbrev The Annotation label abbreviation.
1038
	 * @return The AnnotationType.
1039
	 */
1040
	protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){
1041
		AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);
1042
		if (annotationType == null) {
1043
			annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
1044
			annotationType.setUuid(uuid);
1045
//			annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1046
			getTermService().save(annotationType);
1047
		}
1048
		return annotationType;
1049
	}
1050

    
1051
	/**
1052
	 * Traverses the classification recursively and stores determined values for every Taxon.
1053
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1054
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1055
	 * @param treeIndex The TreeIndex at the current level.
1056
	 * @param fetchLevel Rank to stop fetching at.
1057
	 * @param state The {@link PesiExportState PesiExportState}.
1058
	 */
1059
	private void traverseTree(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, Rank fetchLevel, PesiExportState state) {
1060
		// Traverse all branches from this childNode until specified fetchLevel is reached.
1061
		StringBuffer localTreeIndex = new StringBuffer(treeIndex);
1062
		Taxon childTaxon = childNode.getTaxon();
1063
		if (childTaxon != null) {
1064
			if (isPesiTaxon(childTaxon)){
1065
				Integer taxonId = state.getDbId(childTaxon);
1066
				TaxonNameBase<?,?> childName = childTaxon.getName();
1067
				if (taxonId != null) {
1068
					Rank childRank = childName.getRank();
1069
					if (childRank != null) {
1070
						if (! childRank.equals(fetchLevel)) {
1071
	
1072
							localTreeIndex.append(taxonId + "#");
1073
							
1074
							saveData(childNode, parentNode, localTreeIndex, state, taxonId);
1075
	
1076
							// Store treeIndex as annotation for further use
1077
							Annotation annotation = Annotation.NewInstance(localTreeIndex.toString(), getTreeIndexAnnotationType(), Language.DEFAULT());
1078
							childNode.addAnnotation(annotation);
1079
	
1080
							for (TaxonNode newNode : childNode.getChildNodes()) {
1081
								if (newNode.getTaxon() != null && isPesiTaxon(newNode.getTaxon())){
1082
									traverseTree(newNode, childNode, localTreeIndex, fetchLevel, state);
1083
								}
1084
							}
1085
							
1086
						} else {
1087
	//						logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1088
							return;
1089
						}
1090
					} else {
1091
						logger.error("Rank is NULL. FetchLevel can not be checked: " + childName.getUuid() + " (" + childName.getTitleCache() + ")");
1092
					}
1093
				} else {
1094
					logger.error("Taxon can not be found in state: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
1095
				}
1096
			}else{
1097
				if (logger.isDebugEnabled()){ 
1098
					logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
1099
				}
1100
			}
1101

    
1102
		} else {
1103
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
1104
		}
1105
	}
1106

    
1107
	/**
1108
	 * Stores values in database for every recursive round.
1109
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1110
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1111
	 * @param treeIndex The TreeIndex at the current level.
1112
	 * @param state The {@link PesiExportState PesiExportState}.
1113
	 * @param currentTaxonFk The TaxonFk to store the values for.
1114
	 */
1115
	private void saveData(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, PesiExportState state, Integer currentTaxonFk) {
1116
		// We are differentiating kingdoms by the nomenclatural code for now.
1117
		// This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1118
		Taxon childTaxon = childNode.getTaxon();
1119
		if (isPesiTaxon(childTaxon)) {
1120
			TaxonBase<?> parentTaxon = null;
1121
			if (parentNode != null) {
1122
				parentTaxon = parentNode.getTaxon();
1123
				
1124
			}
1125

    
1126
			invokeParentTaxonFkAndTreeIndex(state.getDbId(parentTaxon), currentTaxonFk,	treeIndex);
1127
		}
1128
		
1129
	}
1130

    
1131
	/**
1132
	 * Inserts values into the Taxon database table.
1133
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1134
	 * @param state The {@link PesiExportState PesiExportState}.
1135
	 * @param stmt The prepared statement.
1136
	 * @return Whether save was successful or not.
1137
	 */
1138
	protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk, Integer currentTaxonFk, StringBuffer treeIndex) {
1139
		try {
1140
			if (parentTaxonFk != null) {
1141
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(1, parentTaxonFk);
1142
			} else {
1143
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(1, null);
1144
			}
1145

    
1146
			if (treeIndex != null) {
1147
				parentTaxonFk_TreeIndex_KingdomFkStmt.setString(2, treeIndex.toString());
1148
			} else {
1149
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(2, null);
1150
			}
1151

    
1152
			if (currentTaxonFk != null) {
1153
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(3, currentTaxonFk);
1154
			} else {
1155
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(3, null);
1156
			}
1157
			
1158
			parentTaxonFk_TreeIndex_KingdomFkStmt.executeUpdate();
1159
			return true;
1160
		} catch (SQLException e) {
1161
			logger.error("ParentTaxonFk (" + parentTaxonFk ==null? "-":parentTaxonFk + ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk == null? "-" :currentTaxonFk) + ": " + e.getMessage());
1162
			e.printStackTrace();
1163
			return false;
1164
		}
1165
	}
1166
	
1167
	protected boolean invokeParentTaxonFk(Integer parentId, Integer childId) {
1168
		try {
1169
			parentTaxonFkStmt.setInt(1, parentId);
1170
			parentTaxonFkStmt.setInt(2, childId);
1171
			parentTaxonFkStmt.executeUpdate();
1172
			return true;
1173
		} catch (SQLException e) {
1174
			logger.warn("ParentTaxonFk (" + parentId ==null? "-":parentId + ") could not be inserted into database for taxon "+ (childId == null? "-" :childId) + ": " + e.getMessage());
1175
			e.printStackTrace();
1176
			return false;
1177
		}
1178
	}
1179

    
1180

    
1181
	/**
1182
	 * Inserts Rank data and KingdomFk into the Taxon database table.
1183
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1184
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1185
	 * @param taxonFk The TaxonFk to store the values for.
1186
	 * @param kindomFk The KingdomFk.
1187
	 * @return Whether save was successful or not.
1188
	 */
1189
	private boolean invokeRankDataAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, Integer taxonFk, Integer kingdomFk) {
1190
		try {
1191
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1192
			if (rankFk != null) {
1193
				rankUpdateStmt.setInt(1, rankFk);
1194
			} else {
1195
				rankUpdateStmt.setObject(1, null);
1196
			}
1197
	
1198
			String rankCache = getRankCache(taxonName, nomenclaturalCode);
1199
			if (rankCache != null) {
1200
				rankUpdateStmt.setString(2, rankCache);
1201
			} else {
1202
				rankUpdateStmt.setObject(2, null);
1203
			}
1204
			
1205
			if (kingdomFk != null) {
1206
				rankUpdateStmt.setInt(3, kingdomFk);
1207
			} else {
1208
				rankUpdateStmt.setObject(3, null);
1209
			}
1210
			
1211
			if (taxonFk != null) {
1212
				rankUpdateStmt.setInt(4, taxonFk);
1213
			} else {
1214
				rankUpdateStmt.setObject(4, null);
1215
			}
1216
			
1217
			rankUpdateStmt.executeUpdate();
1218
			return true;
1219
		} catch (SQLException e) {
1220
			logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());
1221
			e.printStackTrace();
1222
			return false;
1223
		}
1224
	}
1225

    
1226
	/**
1227
	 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1228
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1229
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1230
	 * @param taxonFk The TaxonFk to store the values for.
1231
	 * @param typeNameFk The TypeNameFk.
1232
	 * @param kindomFk The KingdomFk.
1233
	 * @param expertFk The ExpertFk.
1234
	 * @param speciesExpertFk The SpeciesExpertFk.
1235
	 * @return Whether save was successful or not.
1236
	 */
1237
	private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, 
1238
			Integer taxonFk, Integer typeNameFk, Integer kingdomFkk) {
1239
		try {
1240
			int index = 1;
1241
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1242
			if (rankFk != null) {
1243
				rankTypeExpertsUpdateStmt.setInt(index++, rankFk);
1244
			} else {
1245
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1246
			}
1247
	
1248
			String rankCache = getRankCache(taxonName, nomenclaturalCode);
1249
			if (rankCache != null) {
1250
				rankTypeExpertsUpdateStmt.setString(index++, rankCache);
1251
			} else {
1252
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1253
			}
1254
			
1255
			if (typeNameFk != null) {
1256
				rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);
1257
			} else {
1258
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1259
			}
1260
			
1261
			if (kingdomFk != null) {
1262
				rankTypeExpertsUpdateStmt.setInt(index++, kingdomFk);
1263
			} else {
1264
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1265
			}
1266
			
1267
//			if (expertFk != null) {
1268
//				rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1269
//			} else {
1270
//				rankTypeExpertsUpdateStmt.setObject(5, null);
1271
//			}
1272
//
1273
//			//TODO handle experts GUIDS
1274
//			if (speciesExpertFk != null) {
1275
//				rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1276
//			} else {
1277
//				rankTypeExpertsUpdateStmt.setObject(6, null);
1278
//			}
1279
//			
1280
			if (taxonFk != null) {
1281
				rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);
1282
			} else {
1283
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1284
			}
1285

    
1286
			rankTypeExpertsUpdateStmt.executeUpdate();
1287
			return true;
1288
		} catch (SQLException e) {
1289
			logger.error("Data could not be inserted into database: " + e.getMessage());
1290
			e.printStackTrace();
1291
			return false;
1292
		} catch (Exception e) {
1293
			logger.error("Some exception occurred: " + e.getMessage());
1294
			e.printStackTrace();
1295
			return false;
1296
		}
1297
	}
1298

    
1299
	/**
1300
	 * Deletes all entries of database tables related to <code>Taxon</code>.
1301
	 * @param state The {@link PesiExportState PesiExportState}.
1302
	 * @return Whether the delete operation was successful or not.
1303
	 */
1304
	protected boolean doDelete(PesiExportState state) {
1305
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
1306
		
1307
		String sql;
1308
		Source destination =  pesiConfig.getDestination();
1309

    
1310
		// Clear Taxon
1311
		sql = "DELETE FROM " + dbTableName;
1312
		destination.setQuery(sql);
1313
		destination.update(sql);
1314
		return true;
1315
	}
1316

    
1317
	/* (non-Javadoc)
1318
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1319
	 */
1320
	@Override
1321
	protected boolean isIgnore(PesiExportState state) {
1322
		return ! state.getConfig().isDoTaxa();
1323
	}
1324

    
1325
	
1326
	/**
1327
	 * Creates the kingdom fk.
1328
	 * @param taxonName
1329
	 * @return
1330
	 */
1331
	@SuppressWarnings("unused")  //used by mapper
1332
	private static Integer getKingdomFk(TaxonNameBase taxonName){
1333
		return PesiTransformer.nomenClaturalCode2Kingdom(taxonName.getNomenclaturalCode());
1334
	}
1335
	
1336
	/**
1337
	 * Creates the parent fk.
1338
	 * @param taxonName
1339
	 * @return
1340
	 */
1341
	@SuppressWarnings("unused")  //used by mapper
1342
	private static Integer getParentTaxonFk(TaxonBase<?> taxonBase, PesiExportState state){
1343
		if (taxonBase.isInstanceOf(Taxon.class)){
1344
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1345
			if (! isMisappliedName(taxon)){
1346
				Set<TaxonNode> nodes = taxon.getTaxonNodes();
1347
				if (nodes.size() == 0){
1348
					if (taxon.getName().getRank().isLower(Rank.KINGDOM())){
1349
						logger.warn("Accepted taxon has no parent. " + taxon.getTitleCache() + ", " +  taxon.getUuid());
1350
					}
1351
				}else if (nodes.size() > 1){
1352
					logger.warn("Taxon has more than 1 node attached. This is not supported by PESI export." +  taxon.getTitleCache() + ", " +  taxon.getUuid());
1353
				}else{
1354
					Taxon parent =nodes.iterator().next().getParent().getTaxon();
1355
					return state.getDbId(parent);
1356
				}
1357
			}
1358
		}
1359
		return null;
1360
	}
1361

    
1362
	/**
1363
	 * Returns the rankFk for the taxon name based on the names nomenclatural code.
1364
	 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1365
	 * @param taxonName
1366
	 * @return
1367
	 */
1368
	@SuppressWarnings("unused")  //used by mapper
1369
	private static Integer getRankFk(TaxonNameBase<?,?> taxonName) {
1370
		return getRankFk(taxonName, taxonName.getNomenclaturalCode());
1371
	}
1372
		
1373
	
1374
	/**
1375
	 * Returns the <code>RankFk</code> attribute.
1376
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1377
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1378
	 * @return The <code>RankFk</code> attribute.
1379
	 * @see MethodMapper
1380
	 */
1381
	private static Integer getRankFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1382
		Integer result = null;
1383
		try {
1384
			if (nomenclaturalCode != null) {
1385
				if (taxonName != null) {
1386
					if (taxonName.getRank() == null) {
1387
						logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1388
					} else {
1389
						result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1390
					}
1391
					if (result == null) {
1392
						logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1393
					}
1394
				}
1395
			}
1396
		} catch (Exception e) {
1397
			e.printStackTrace();
1398
		}
1399
		return result;
1400
	}
1401

    
1402
	/**
1403
	 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1404
	 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1405
	 * @param taxonName
1406
	 * @return
1407
	 */
1408
	@SuppressWarnings("unused")  //used by mapper
1409
	private static String getRankCache(TaxonNameBase<?,?> taxonName) {
1410
		return getRankCache(taxonName, taxonName.getNomenclaturalCode());
1411
	}
1412

    
1413
	
1414
	/**
1415
	 * Returns the <code>RankCache</code> attribute.
1416
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1417
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1418
	 * @return The <code>RankCache</code> attribute.
1419
	 * @see MethodMapper
1420
	 */
1421
	private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1422
		String result = null;
1423
		try {
1424
			if (nomenclaturalCode != null) {
1425
				result = PesiTransformer.rank2RankCache(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1426
			}
1427
		} catch (Exception e) {
1428
			e.printStackTrace();
1429
		}
1430
		return result;
1431
	}
1432

    
1433
	
1434
	/**
1435
	 * Returns the <code>DisplayName</code> attribute.
1436
	 * @param taxon The {@link TaxonBase Taxon}.
1437
	 * @return The <code>DisplayName</code> attribute.
1438
	 * @see MethodMapper
1439
	 */
1440
	@SuppressWarnings("unused")  //used by Mapper
1441
	private static String getDisplayName(TaxonBase<?> taxon) {
1442
		TaxonNameBase<?,?> taxonName = taxon.getName();
1443
		String result = getDisplayName(taxonName);
1444
		if (isMisappliedName(taxon)){
1445
			result = result + " " + getAuthorString(taxon);
1446
		}
1447
		return result;
1448
	}
1449
	
1450
	/**
1451
	 * Returns the <code>AuthorString</code> attribute.
1452
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1453
	 * @return The <code>AuthorString</code> attribute.
1454
	 * @see MethodMapper
1455
	 */
1456
	@SuppressWarnings("unused") //used by mapper
1457
	protected static String getAuthorString(TaxonBase<?> taxon) {
1458
		try {
1459
			String result = null;
1460
			boolean isNonViralName = false;
1461
			String authorshipCache = null;
1462
			TaxonNameBase<?,?> taxonName = taxon.getName();
1463
			if (taxonName != null && taxonName.isInstanceOf(NonViralName.class)){
1464
				authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();
1465
				isNonViralName = true;
1466
			}
1467
			result = authorshipCache;
1468
			
1469
			// For a misapplied names there are special rules
1470
			if (isMisappliedName(taxon)){
1471
				if (taxon.getSec() != null){
1472
					String secTitle = taxon.getSec().getTitleCache();
1473
					if (! secTitle.startsWith("auct")){
1474
						secTitle = "sensu " + secTitle;
1475
					}else if (secTitle.equals("auct")){  //may be removed once the title cache is generated correctly for references with title auct. #
1476
						secTitle = "auct.";
1477
					}
1478
					return secTitle;
1479
				}else if (StringUtils.isBlank(authorshipCache)) {
1480
					// Set authorshipCache to "auct."
1481
					result = PesiTransformer.AUCT_STRING;
1482
				}else{
1483
					result = PesiTransformer.AUCT_STRING;
1484
//					result = authorshipCache;
1485
				}
1486
			}
1487
			
1488
			if (taxonName == null){
1489
				logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1490
			}else if (! isNonViralName){
1491
				logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1492
			}
1493
			
1494
			if (StringUtils.isBlank(result)) {
1495
				return null;
1496
			} else {
1497
				return result;
1498
			}
1499
		} catch (Exception e) {
1500
			e.printStackTrace();
1501
			return null;
1502
		}
1503
		
1504
	}
1505
		
1506
	
1507
	/**
1508
	 * Returns the <code>DisplayName</code> attribute.
1509
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1510
	 * @return The <code>DisplayName</code> attribute.
1511
	 * @see MethodMapper
1512
	 */
1513
	@SuppressWarnings("unused")  //used by Mapper
1514
	private static String getDisplayName(TaxonNameBase<?,?> taxonName) {
1515
		// TODO: extension?
1516
		if (taxonName == null) {
1517
			return null;
1518
		}else{
1519
			INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1520
			HTMLTagRules tagRules = new HTMLTagRules().
1521
					addRule(TagEnum.name, "i").
1522
					addRule(TagEnum.nomStatus, "@status@");
1523
			
1524
			NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1525
			String result = cacheStrategy.getFullTitleCache(nvn, tagRules);
1526
			cacheStrategy = null;
1527
			nvn = null;
1528
			return result.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");
1529
		}
1530
	}
1531
	
1532

    
1533
	/**
1534
	 * Returns the <code>WebShowName</code> attribute for a taxon.
1535
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1536
	 * @return The <code>WebShowName</code> attribute.
1537
	 * @see MethodMapper
1538
	*/
1539
	@SuppressWarnings("unused")
1540
	private static String getWebShowName(TaxonBase<?> taxon) {
1541
		TaxonNameBase<?,?> taxonName = taxon.getName();
1542
		String result = getWebShowName(taxonName);
1543
		if (isMisappliedName(taxon)){
1544
			result = result + " " + getAuthorString(taxon);
1545
		}
1546
		return result;
1547
	}
1548
	
1549
	/**
1550
	 * Returns the <code>WebShowName</code> attribute.
1551
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1552
	 * @return The <code>WebShowName</code> attribute.
1553
	 * @see MethodMapper
1554
	 */
1555
	private static String getWebShowName(TaxonNameBase<?,?> taxonName) {
1556
		//TODO extensions?
1557
		if (taxonName == null) {
1558
			return null;
1559
		}else{
1560
			INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1561
		
1562
			HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");
1563
			NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1564
			String result = cacheStrategy.getTitleCache(nvn, tagRules);
1565
			cacheStrategy = null;
1566
			nvn = null;
1567
			return result;
1568
		}
1569
	}
1570

    
1571
 	
1572
	/**
1573
	 * Returns the <code>WebSearchName</code> attribute.
1574
	 * @param taxonName The {@link NonViralName NonViralName}.
1575
	 * @return The <code>WebSearchName</code> attribute.
1576
	 * @see MethodMapper
1577
	 */
1578
	@SuppressWarnings("unused")
1579
	private static String getWebSearchName(TaxonNameBase<?,?> taxonName) {
1580
		//TODO extensions?
1581
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1582
		NonViralNameDefaultCacheStrategy<NonViralName<?>> strategy = getCacheStrategy(nvn);
1583
		String result = strategy.getNameCache(nvn);
1584
		strategy = null;
1585
		nvn = null;
1586
		return result;
1587
	}
1588

    
1589

    
1590
	/**
1591
	 * Returns the <code>FullName</code> attribute.
1592
	 * @param taxonName The {@link NonViralName NonViralName}.
1593
	 * @return The <code>FullName</code> attribute.
1594
	 * @see MethodMapper
1595
	 */
1596
	@SuppressWarnings("unused")
1597
	private static String getFullName(TaxonNameBase taxonName) {
1598
		//TODO extensions?
1599
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1600
		String result = getCacheStrategy(nvn).getTitleCache(nvn);
1601
		Iterator<TaxonBase> taxa = taxonName.getTaxa().iterator();
1602
		if (taxonName.getTaxa().size() >0){
1603
			if (taxonName.getTaxa().size() == 1){
1604
				TaxonBase taxon = taxa.next();
1605
				if (isMisappliedName(taxon)){
1606
					result = result + " " + getAuthorString(taxon);
1607
				}
1608
				taxon = null;
1609
			}
1610
		}
1611
		taxa = null;
1612
		nvn = null;
1613
		return result;
1614
	}
1615
	
1616
	/**
1617
	 * Returns the <code>FullName</code> attribute.
1618
	 * @param taxon The {@link TaxonBase taxon}.
1619
	 * @return The <code>FullName</code> attribute.
1620
	 * @see MethodMapper
1621
	 */
1622
	/*@SuppressWarnings("unused")
1623
	private static String getFullName(TaxonBase taxon) {
1624
		//TODO extensions?
1625
		TaxonNameBase name = taxon.getName();
1626
		String result = getFullName(name);
1627
		if (isMisappliedName(taxon)){
1628
			result = result + " " + getAuthorString(taxon);
1629
		}
1630
		
1631
		return result;
1632
	}
1633
*/
1634
	
1635
	/**
1636
	 * Returns the nomenclatural reference which is the reference
1637
	 * including the detail (microreference).
1638
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1639
	 * @return The <code>AuthorString</code> attribute.
1640
	 * @see MethodMapper
1641
	 */
1642
	@SuppressWarnings("unused")
1643
	private static String getNomRefString(TaxonNameBase<?,?> taxonName) {
1644
		INomenclaturalReference ref = taxonName.getNomenclaturalReference();
1645
		return ref == null ? null : ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());
1646
	}
1647
	
1648

    
1649
	/**
1650
	 * Returns the <code>NameStatusFk</code> attribute.
1651
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1652
	 * @return The <code>NameStatusFk</code> attribute.
1653
	 * @see MethodMapper
1654
	 */
1655
	@SuppressWarnings("unused")
1656
	private static Integer getNameStatusFk(TaxonNameBase<?,?> taxonName) {
1657
		Integer result = null;
1658

    
1659
		NomenclaturalStatus state = getNameStatus(taxonName);
1660
		if (state != null) {
1661
			result = PesiTransformer.nomStatus2nomStatusFk(state.getType());
1662
		}
1663
		return result;
1664
	}
1665
	
1666
	/**
1667
	 * Returns the <code>NameStatusCache</code> attribute.
1668
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1669
	 * @return The <code>NameStatusCache</code> attribute.
1670
	 * @throws UndefinedTransformerMethodException 
1671
	 * @see MethodMapper
1672
	 */
1673
	@SuppressWarnings("unused")
1674
	private static String getNameStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1675
		String result = null;
1676
		NomenclaturalStatus status = getNameStatus(taxonName);
1677
		if (status != null) {
1678
			result = state.getTransformer().getCacheByNomStatus(status.getType());
1679
		}
1680
		return result;
1681
	}
1682
	
1683
	
1684
	private static NomenclaturalStatus getNameStatus(TaxonNameBase<?,?> taxonName) {
1685
		try {
1686
			if (taxonName != null && (taxonName.isInstanceOf(NonViralName.class))) {
1687
				NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);
1688
				Set<NomenclaturalStatus> states = nonViralName.getStatus();
1689
				if (states.size() == 1) {
1690
					NomenclaturalStatus status = states.iterator().next();
1691
					return status;
1692
				} else if (states.size() > 1) {
1693
					logger.error("This TaxonName has more than one Nomenclatural Status: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1694
				}
1695
			}
1696
		
1697
		} catch (Exception e) {
1698
			e.printStackTrace();
1699
		}
1700
		return null;
1701
	}
1702
	/**
1703
	 * Returns the <code>TaxonStatusFk</code> attribute.
1704
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1705
	 * @param state The {@link PesiExportState PesiExportState}.
1706
	 * @return The <code>TaxonStatusFk</code> attribute.
1707
	 * @see MethodMapper
1708
	 */
1709
	private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {
1710
		Integer result = null;
1711
		
1712
		try {
1713
			if (isMisappliedName(taxon)) {
1714
				Synonym synonym = Synonym.NewInstance(null, null);
1715
				
1716
				// This works as long as only the instance is important to differentiate between TaxonStatus.
1717
				result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in Datawarehouse now.
1718
			} else {
1719
				result = PesiTransformer.taxonBase2statusFk(taxon);
1720
			}
1721
		
1722
		} catch (Exception e) {
1723
			e.printStackTrace();
1724
		}
1725
		return result;
1726
	}
1727
	
1728
	/**
1729
	 * Returns the <code>TaxonStatusCache</code> attribute.
1730
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1731
	 * @param state The {@link PesiExportState PesiExportState}.
1732
	 * @return The <code>TaxonStatusCache</code> attribute.
1733
	 * @throws UndefinedTransformerMethodException 
1734
	 * @see MethodMapper
1735
	 */
1736
	@SuppressWarnings("unused")
1737
	private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) throws UndefinedTransformerMethodException {
1738
		return state.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon, state));
1739
	}
1740
	
1741
	/**
1742
	 * Returns the <code>TypeNameFk</code> attribute.
1743
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1744
	 * @param state The {@link PesiExportState PesiExportState}.
1745
	 * @return The <code>TypeNameFk</code> attribute.
1746
	 * @see MethodMapper
1747
	 */
1748
	private static Integer getTypeNameFk(TaxonNameBase<?,?> taxonNameBase, PesiExportState state) {
1749
		Integer result = null;
1750
		if (taxonNameBase != null) {
1751
			Set<NameTypeDesignation> nameTypeDesignations = taxonNameBase.getNameTypeDesignations();
1752
			if (nameTypeDesignations.size() == 1) {
1753
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1754
				if (nameTypeDesignation != null) {
1755
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1756
					if (typeName != null) {
1757
						result = state.getDbId(typeName);
1758
					}
1759
				}
1760
			} else if (nameTypeDesignations.size() > 1) {
1761
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonNameBase.getUuid() + " (" + taxonNameBase.getTitleCache() + ")");
1762
			}
1763
		}
1764
		return result;
1765
	}
1766
	
1767
	/**
1768
	 * Returns the <code>TypeFullnameCache</code> attribute.
1769
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1770
	 * @return The <code>TypeFullnameCache</code> attribute.
1771
	 * @see MethodMapper
1772
	 */
1773
	@SuppressWarnings("unused")
1774
	private static String getTypeFullnameCache(TaxonNameBase<?,?> taxonName) {
1775
		String result = null;
1776
		
1777
		try {
1778
		if (taxonName != null) {
1779
			Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
1780
			if (nameTypeDesignations.size() == 1) {
1781
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1782
				if (nameTypeDesignation != null) {
1783
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1784
					if (typeName != null) {
1785
						result = typeName.getTitleCache();
1786
					}
1787
				}
1788
			} else if (nameTypeDesignations.size() > 1) {
1789
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1790
			}
1791
		}
1792
		
1793
		} catch (Exception e) {
1794
			e.printStackTrace();
1795
		}
1796
		return result;
1797
	}
1798

    
1799
	
1800
	/**
1801
	 * Returns the <code>QualityStatusFk</code> attribute.
1802
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1803
	 * @return The <code>QualityStatusFk</code> attribute.
1804
	 * @see MethodMapper
1805
	 */
1806
	private static Integer getQualityStatusFk(TaxonNameBase taxonName) {
1807
		BitSet sources = getSources(taxonName);
1808
		return PesiTransformer.getQualityStatusKeyBySource(sources, taxonName);
1809
	}
1810

    
1811
	
1812
	/**
1813
	 * Returns the <code>QualityStatusCache</code> attribute.
1814
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1815
	 * @return The <code>QualityStatusCache</code> attribute.
1816
	 * @throws UndefinedTransformerMethodException 
1817
	 * @see MethodMapper
1818
	 */
1819
	@SuppressWarnings("unused")
1820
	private static String getQualityStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1821
		return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));
1822
	}
1823

    
1824
	
1825
	/**
1826
	 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1827
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1828
	 * @return The <code>TypeDesignationStatusFk</code> attribute.
1829
	 * @see MethodMapper
1830
	 */
1831
	@SuppressWarnings("unused")
1832
	private static Integer getTypeDesignationStatusFk(TaxonNameBase<?,?> taxonName) {
1833
		Integer result = null;
1834
		
1835
		try {
1836
		if (taxonName != null) {
1837
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1838
			if (typeDesignations.size() == 1) {
1839
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1840
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1841
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);
1842
			} else if (typeDesignations.size() > 1) {
1843
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1844
			}
1845
		}
1846
		
1847
		} catch (Exception e) {
1848
			e.printStackTrace();
1849
		}
1850
		return result;
1851
	}
1852

    
1853
	/**
1854
	 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1855
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1856
	 * @return The <code>TypeDesignationStatusCache</code> attribute.
1857
	 * @see MethodMapper
1858
	 */
1859
	@SuppressWarnings("unused")
1860
	private static String getTypeDesignationStatusCache(TaxonNameBase<?,?> taxonName) {
1861
		String result = null;
1862
		
1863
		try {
1864
		if (taxonName != null) {
1865
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1866
			if (typeDesignations.size() == 1) {
1867
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1868
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1869
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);
1870
			} else if (typeDesignations.size() > 1) {
1871
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1872
			}
1873
		}
1874
		
1875
		} catch (Exception e) {
1876
			e.printStackTrace();
1877
		}
1878
		return result;
1879
	}
1880
	
1881
	/**
1882
	 * Returns the <code>FossilStatusFk</code> attribute.
1883
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1884
	 * @return The <code>FossilStatusFk</code> attribute.
1885
	 * @see MethodMapper
1886
	 */
1887
	@SuppressWarnings("unused")
1888
	private static Integer getFossilStatusFk(IdentifiableEntity<?> identEntity, PesiExportState state) {
1889
		Integer result = null;
1890
		
1891
		Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
1892
		if (fossilStatuus.size() == 0){
1893
			return null;
1894
		}else if (fossilStatuus.size() > 1){
1895
			logger.warn("More than 1 fossil status given for " +  identEntity.getTitleCache() + " " + identEntity.getUuid());
1896
		}
1897
		String fossilStatus = fossilStatuus.iterator().next();
1898
		
1899
		int statusFk = state.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus);
1900
		return statusFk;
1901
	}
1902
	
1903
	/**
1904
	 * Returns the <code>FossilStatusCache</code> attribute.
1905
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1906
	 * @return The <code>FossilStatusCache</code> attribute.
1907
	 * @see MethodMapper
1908
	 */
1909
	@SuppressWarnings("unused")
1910
	private static String getFossilStatusCache(IdentifiableEntity<?> identEntity, PesiExportState state) {
1911
		String result = null;
1912
		Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
1913
		if (fossilStatuus.size() == 0){
1914
			return null;
1915
		}
1916
		for (String strFossilStatus : fossilStatuus){
1917
			result = CdmUtils.concat(";", result, strFossilStatus);
1918
		}
1919
		return result;
1920
	}
1921
	
1922
	/**
1923
	 * Returns the <code>IdInSource</code> attribute.
1924
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1925
	 * @return The <code>IdInSource</code> attribute.
1926
	 * @see MethodMapper
1927
	 */
1928
	@SuppressWarnings("unused")
1929
	private static String getIdInSource(IdentifiableEntity taxonName) {
1930
		String result = null;
1931
		
1932
		try {
1933
			Set<IdentifiableSource> sources = getPesiSources(taxonName);
1934
			if (sources.size() > 1){
1935
				logger.warn("There is > 1 Pesi source. This is not yet handled.");
1936
			}
1937
			if (sources.size() == 0){
1938
				logger.warn("There is no Pesi source!" +taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1939
			}
1940
			for (IdentifiableSource source : sources) {
1941
				Reference<?> ref = source.getCitation();
1942
				UUID refUuid = ref.getUuid();
1943
				String idInSource = source.getIdInSource();
1944
				if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed)){
1945
					result = idInSource != null ? ("NameId: " + source.getIdInSource()) : null;
1946
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
1947
					result = idInSource != null ? ("TAX_ID: " + source.getIdInSource()) : null;
1948
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
1949
					result = idInSource != null ? ("tu_id: " + source.getIdInSource()) : null;
1950
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){  //Index Fungorum
1951
					result = idInSource != null ? ("if_id: " + source.getIdInSource()) : null;
1952
				}else{
1953
					if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
1954
				}
1955
				
1956
				String sourceIdNameSpace = source.getIdNamespace();
1957
				if (sourceIdNameSpace != null) {
1958
					if (sourceIdNameSpace.equals(PesiTransformer.STR_NAMESPACE_NOMINAL_TAXON)) {
1959
						result =  idInSource != null ? ("Nominal Taxon from TAX_ID: " + source.getIdInSource()):null;
1960
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_EPITHET_NAMESPACE)) {
1961
						result =  idInSource != null ? ("Inferred epithet from TAX_ID: " + source.getIdInSource()) : null;
1962
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_GENUS_NAMESPACE)) {
1963
						result =  idInSource != null ? ("Inferred genus from TAX_ID: " + source.getIdInSource()):null;
1964
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {
1965
						result =  idInSource != null ? ("Potential combination from TAX_ID: " + source.getIdInSource()):null;
1966
					} 
1967
				}
1968
				if (result == null) {
1969
					logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +", sourceIdNameSpace: " + source.getIdNamespace()+")");
1970
				}
1971
			}
1972
		} catch (Exception e) {
1973
			e.printStackTrace();
1974
			logger.error("An error occurs while creating idInSource..." + taxonName.getUuid() + " (" + taxonName.getTitleCache()+ e.getMessage());
1975
		}
1976

    
1977
		if (result == null) {
1978
			logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1979
		}
1980
		return result;
1981
	}
1982
	
1983
	/**
1984
	 * Returns the idInSource for a given TaxonName only.
1985
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1986
	 * @return The idInSource.
1987
	 */
1988
	private static String getIdInSourceOnly(IdentifiableEntity identEntity) {
1989
		String result = null;
1990
		
1991
		// Get the sources first
1992
		Set<IdentifiableSource> sources = getPesiSources(identEntity);
1993

    
1994
		// Determine the idInSource
1995
		if (sources.size() == 1) {
1996
			IdentifiableSource source = sources.iterator().next();
1997
			if (source != null) {
1998
				result = source.getIdInSource();
1999
			}
2000
		} else if (sources.size() > 1) {
2001
			int count = 1;
2002
			result = "";
2003
			for (IdentifiableSource source : sources) {
2004
				result += source.getIdInSource();
2005
				if (count < sources.size()) {
2006
					result += "; ";
2007
				}
2008
				count++;
2009
			}
2010

    
2011
		}
2012
		
2013
		return result;
2014
	}
2015
	
2016
	/**
2017
	 * Returns the Sources for a given TaxonName only.
2018
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2019
	 * @return The Sources.
2020
	 */
2021
	private static Set<IdentifiableSource> getPesiSources(IdentifiableEntity identEntity) {
2022
		Set<IdentifiableSource> sources = new java.util.HashSet<IdentifiableSource>();
2023

    
2024
		//Taxon Names
2025
		if (identEntity.isInstanceOf(TaxonNameBase.class)){
2026
			// Sources from TaxonName
2027
			TaxonNameBase taxonName = CdmBase.deproxy(identEntity, TaxonNameBase.class);
2028
			Set<IdentifiableSource> testSources = identEntity.getSources();
2029
			sources = filterPesiSources(identEntity.getSources());
2030
			
2031
			if (sources.size() == 0 && testSources.size()>0){
2032
				IdentifiableSource source = testSources.iterator().next();
2033
				logger.warn("There are sources, but they are no pesi sources!!!" + source.getIdInSource() + " - " + source.getIdNamespace() + " - "+source.getCitation().generateTitle());
2034
			}
2035
			if (sources.size() > 1) {
2036
				logger.warn("This TaxonName has more than one Source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() + ")");
2037
			}
2038
			
2039
			// name has no PESI source, take sources from TaxonBase
2040
			if (sources == null || sources.isEmpty()) {
2041
				Set<TaxonBase> taxa = taxonName.getTaxonBases();
2042
				for (TaxonBase taxonBase: taxa){
2043
					sources.addAll(filterPesiSources(taxonBase.getSources()));
2044
				}
2045
			}
2046

    
2047
		//for TaxonBases
2048
		}else if (identEntity.isInstanceOf(TaxonBase.class)){
2049
			sources = filterPesiSources(identEntity.getSources());	
2050
		}
2051

    
2052
		/*TODO: deleted only for testing the inferred synonyms 
2053
		if (sources == null || sources.isEmpty()) {
2054
			logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2055
		}else if (sources.size() > 1){
2056
			logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2057
		}
2058
		*/
2059
		return sources;
2060
	}
2061
	
2062
	// return all sources with a PESI reference	
2063
	private static Set<IdentifiableSource> filterPesiSources(Set<? extends IdentifiableSource> sources) {
2064
		Set<IdentifiableSource> result = new HashSet<IdentifiableSource>();
2065
		for (IdentifiableSource source : sources){
2066
			Reference ref = source.getCitation();
2067
			UUID refUuid = ref.getUuid();
2068
			if (refUuid.equals(PesiTransformer.uuidSourceRefEuroMed) || 
2069
				refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)||
2070
				refUuid.equals(PesiTransformer.uuidSourceRefErms)||
2071
				refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum) ||
2072
				refUuid.equals(PesiTransformer.uuidSourceRefAuct)){
2073
				result.add(source);
2074
			}
2075
		}
2076
		return result;
2077
	}
2078

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

    
2466
	
2467
	/**
2468
	 * Returns the CDM to PESI specific export mappings.
2469
	 * @return The {@link PesiExportMapping PesiExportMapping}.
2470
	 */
2471
	private PesiExportMapping getMapping() {
2472
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2473
		
2474
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2475
		mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2476
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2477
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
2478
		
2479
		mapping.addMapper(MethodMapper.NewInstance("GUID", this));
2480
		
2481
		mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));
2482
		mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));
2483
		mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently
2484
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));
2485
		
2486
		// DisplayName
2487
		mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));
2488

    
2489
		// FossilStatus (Fk, Cache)
2490
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, IdentifiableEntity.class, PesiExportState.class));
2491
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, IdentifiableEntity.class, PesiExportState.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2492
		
2493
		//handled by name mapping
2494
		mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2495
		mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2496
		
2497
		//experts
2498
		ExtensionType extensionTypeSpeciesExpertName = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
2499
		mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));
2500
		ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
2501
		mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));
2502
		
2503
//		mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class));  //by AM, doesn't work, FK exception
2504
		mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2505
		
2506
		addNameMappers(mapping);
2507

    
2508
		return mapping;
2509
	}
2510
	
2511
	/**
2512
	 * Returns the CDM to PESI specific export mappings.
2513
	 * @param state 
2514
	 * @return The {@link PesiExportMapping PesiExportMapping}.
2515
	 * @throws UndefinedTransformerMethodException 
2516
	 */
2517
	private PesiExportMapping getPureNameMapping(PesiExportState state) throws UndefinedTransformerMethodException {
2518
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2519
		
2520
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2521

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

    
2524
		mapping.addMapper(MethodMapper.NewInstance("KingdomFk", this, TaxonNameBase.class));
2525
		mapping.addMapper(MethodMapper.NewInstance("RankFk", this, TaxonNameBase.class));
2526
		mapping.addMapper(MethodMapper.NewInstance("RankCache", this, TaxonNameBase.class));
2527
		mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER , PesiTransformer.T_STATUS_UNACCEPTED));
2528
		mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR , state.getTransformer().getTaxonStatusCacheByKey( PesiTransformer.T_STATUS_UNACCEPTED)));
2529
		mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));  
2530
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));
2531
		
2532
		// DisplayName
2533
		mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));
2534
		
2535
		mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2536
		mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2537
		
2538
		addNameMappers(mapping);
2539
		//TODO add author mapper, TypeNameFk
2540

    
2541
		return mapping;
2542
	}
2543

    
2544
	private void addNameMappers(PesiExportMapping mapping) {
2545
		mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2546
		mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2547
		mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));
2548
		mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2549
		
2550
//		mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName"));  //does not work as we need other cache strategy
2551
		mapping.addMapper(MethodMapper.NewInstance("WebSearchName", this, TaxonNameBase.class));
2552
		
2553
//		mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName"));    //does not work as we need other cache strategy
2554
		mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonNameBase.class));
2555
		
2556
		
2557
		mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonNameBase.class));
2558
		
2559
		mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));
2560
		mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2561
		mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonNameBase.class));
2562
		//TODO TypeNameFk
2563
		
2564
		//quality status
2565
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonNameBase.class));
2566
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2567
		
2568
		mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));
2569
		mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );
2570

    
2571
		//mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2572

    
2573
	}
2574
	
2575
	private PesiExportMapping getSynRelMapping() {
2576
		PesiExportMapping mapping = new PesiExportMapping(dbTableNameSynRel);
2577
		
2578
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase.class, PesiExportState.class));
2579
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase.class, PesiExportState.class));
2580
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this,  RelationshipBase.class));
2581
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
2582
		mapping.addMapper(MethodMapper.NewInstance("Notes", this,  RelationshipBase.class));
2583

    
2584
		return mapping;
2585
	}
2586

    
2587

    
2588
}
(17-17/18)