Project

General

Profile

Download (81.3 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.util.ArrayList;
17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Set;
20
import java.util.UUID;
21

    
22
import org.apache.commons.lang.StringUtils;
23
import org.apache.log4j.Logger;
24
import org.joda.time.DateTime;
25
import org.joda.time.format.DateTimeFormat;
26
import org.joda.time.format.DateTimeFormatter;
27
import org.springframework.stereotype.Component;
28
import org.springframework.transaction.TransactionStatus;
29

    
30
import eu.etaxonomy.cdm.common.CdmUtils;
31
import eu.etaxonomy.cdm.io.common.Source;
32
import eu.etaxonomy.cdm.io.common.mapping.out.DbExtensionMapper;
33
import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
34
import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
35
import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
36
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
37
import eu.etaxonomy.cdm.io.common.mapping.out.ObjectChangeMapper;
38
import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;
39
import eu.etaxonomy.cdm.model.common.Annotation;
40
import eu.etaxonomy.cdm.model.common.AnnotationType;
41
import eu.etaxonomy.cdm.model.common.CdmBase;
42
import eu.etaxonomy.cdm.model.common.Extension;
43
import eu.etaxonomy.cdm.model.common.ExtensionType;
44
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
45
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
46
import eu.etaxonomy.cdm.model.common.Language;
47
import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
48
import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
49
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
50
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
51
import eu.etaxonomy.cdm.model.name.NonViralName;
52
import eu.etaxonomy.cdm.model.name.Rank;
53
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
54
import eu.etaxonomy.cdm.model.name.ZoologicalName;
55
import eu.etaxonomy.cdm.model.reference.Reference;
56
import eu.etaxonomy.cdm.model.taxon.Classification;
57
import eu.etaxonomy.cdm.model.taxon.Synonym;
58
import eu.etaxonomy.cdm.model.taxon.Taxon;
59
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
60
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
61
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
62
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
63
import eu.etaxonomy.cdm.persistence.query.MatchMode;
64
import eu.etaxonomy.cdm.strategy.cache.TaggedText;
65

    
66
/**
67
 * The export class for {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames}.<p>
68
 * Inserts into DataWarehouse database table <code>Taxon</code>.
69
 * It is divided into four phases:<p><ul>
70
 * <li>Phase 1:	Export of all {@link eu.etaxonomy.cdm.model.name.TaxonNameBase TaxonNames} except some data exported in the following phases.
71
 * <li>Phase 2:	Export of additional data: ParenTaxonFk and TreeIndex.
72
 * <li>Phase 3:	Export of additional data: Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk.
73
 * <li>Phase 4:	Export of Inferred Synonyms.</ul>
74
 * @author e.-m.lee
75
 * @date 23.02.2010
76
 *
77
 */
78
@Component
79
public class PesiTaxonExport extends PesiExportBase {
80
	private static final Logger logger = Logger.getLogger(PesiTaxonExport.class);
81
	private static final Class<? extends CdmBase> standardMethodParameter = TaxonBase.class;
82

    
83
	private static int modCount = 1000;
84
	private static final String dbTableName = "Taxon";
85
	private static final String pluralString = "Taxa";
86
	private static final String parentPluralString = "Taxa";
87
	private PreparedStatement parentTaxonFk_TreeIndex_KingdomFkStmt;
88
	private PreparedStatement rankTypeExpertsUpdateStmt;
89
	private PreparedStatement rankUpdateStmt;
90
	private NomenclaturalCode nomenclaturalCode;
91
	private Integer kingdomFk;
92
	private HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();
93
	private List<Rank> rankList = new ArrayList<Rank>();
94
	private static final UUID uuidTreeIndex = UUID.fromString("28f4e205-1d02-4d3a-8288-775ea8413009");
95
	private AnnotationType treeIndexAnnotationType;
96
	private static ExtensionType lastActionExtensionType;
97
	private static ExtensionType lastActionDateExtensionType;
98
	private static ExtensionType expertNameExtensionType;
99
	private static ExtensionType speciesExpertNameExtensionType;
100
	private static ExtensionType cacheCitationExtensionType;
101
	private static ExtensionType expertUserIdExtensionType;
102
	private static ExtensionType speciesExpertUserIdExtensionType;
103
	
104
	/**
105
	 * @return the treeIndexAnnotationType
106
	 */
107
	protected AnnotationType getTreeIndexAnnotationType() {
108
		return treeIndexAnnotationType;
109
	}
110

    
111
	/**
112
	 * @param treeIndexAnnotationType the treeIndexAnnotationType to set
113
	 */
114
	protected void setTreeIndexAnnotationType(AnnotationType treeIndexAnnotationType) {
115
		this.treeIndexAnnotationType = treeIndexAnnotationType;
116
	}
117

    
118
	enum NamePosition {
119
		beginning,
120
		end,
121
		between,
122
		alone,
123
		nowhere
124
	}
125

    
126
	public PesiTaxonExport() {
127
		super();
128
	}
129

    
130
	/* (non-Javadoc)
131
	 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
132
	 */
133
	@Override
134
	public Class<? extends CdmBase> getStandardMethodParameter() {
135
		return standardMethodParameter;
136
	}
137

    
138
	/* (non-Javadoc)
139
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
140
	 */
141
	@Override
142
	protected boolean doCheck(PesiExportState state) {
143
		boolean result = true;
144
		return result;
145
	}
146
	
147
	
148
	/**
149
	 * Returns the CDM to PESI specific export mappings.
150
	 * @return The {@link PesiExportMapping PesiExportMapping}.
151
	 */
152
	private PesiExportMapping getMapping() {
153
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
154
		ExtensionType extensionType = null;
155
		
156
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
157
		mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
158
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
159
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
160
		// QualityStatus (Fk, Cache)
161
		extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidQualityStatus);
162
		if (extensionType != null) {
163
			mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "QualityStatusCache"));
164
		} else {
165
			mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this));
166
		}
167
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this)); // PesiTransformer.QualityStatusCache2QualityStatusFk?
168

    
169
		mapping.addMapper(MethodMapper.NewInstance("GUID", this));
170
		//TODO implement again
171
//		mapping.addMapper(MethodMapper.NewInstance("IdInSource", this));
172

    
173
		mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));
174
		mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));
175
//		mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this));
176
		mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this.getClass(), "getOriginalDB", IdentifiableEntity.class) );
177
		
178
		mapping.addMapper(MethodMapper.NewInstance("LastAction", this.getClass(), "getLastAction",  IdentifiableEntity.class));
179
		mapping.addMapper(MethodMapper.NewInstance("LastActionDate", this.getClass(), "getLastActionDate",  IdentifiableEntity.class));
180
		mapping.addMapper(MethodMapper.NewInstance("ExpertName", this));
181
		mapping.addMapper(MethodMapper.NewInstance("SpeciesExpertName", this));
182

    
183
		mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently
184
		
185
		
186
		mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
187
		
188
		addNameMappers(mapping);
189

    
190
		return mapping;
191
	}
192
	
193
	/**
194
	 * Returns the CDM to PESI specific export mappings.
195
	 * @return The {@link PesiExportMapping PesiExportMapping}.
196
	 */
197
	private PesiExportMapping getNameMapping() {
198
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
199
		
200
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
201

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

    
204
		mapping.addMapper(MethodMapper.NewInstance("LastAction", this.getClass(), "getLastAction", IdentifiableEntity.class));
205
		mapping.addMapper(MethodMapper.NewInstance("LastActionDate",  this.getClass(), "getLastAction", IdentifiableEntity.class));
206
		mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this.getClass(), "getOriginalDB", IdentifiableEntity.class) );
207
		addNameMappers(mapping);
208
		
209
		//TODO add author mapper, taxonStatusFk, TaxonStatusCache, TypeNameFk
210
//		mapping.addMapper(MethodMapper.NewInstance("IdInSource", this));
211
//	immer 2 f?r E+M ?	mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this)); // PesiTransformer.QualityStatusCache2QualityStatusFk?
212
//		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
213

    
214
		return mapping;
215
	}
216

    
217
	private void addNameMappers(PesiExportMapping mapping) {
218
		ExtensionType extensionType;
219
		mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
220
		mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
221
		mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));
222
		mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
223
		mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName"));
224
		mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName"));
225
		//TODO FIXME incorrect mapping -> should be ref +  microref but is only microref
226
		mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "NomRefString"));
227
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));
228
		
229
		// DisplayName
230
		extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidDisplayName);		
231
		if (extensionType != null) {
232
			mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "DisplayName"));
233
		} else {
234
			mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));
235
		}
236

    
237
		mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));
238
		mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonNameBase.class));
239
		mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonNameBase.class));
240
		//TODO TypeNameFk
241
		
242
		// FossilStatus (Fk, Cache)
243
		extensionType = (ExtensionType)getTermService().find(ErmsTransformer.uuidFossilStatus);
244
		if (extensionType != null) {
245
			mapping.addMapper(DbExtensionMapper.NewInstance(extensionType, "FossilStatusCache"));
246
		} else {
247
			mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, TaxonNameBase.class));
248
		}
249
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, TaxonNameBase.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
250
	}
251

    
252
	/* (non-Javadoc)
253
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
254
	 */
255
	@Override
256
	protected void doInvoke(PesiExportState state) {
257
		try {
258
			logger.info("*** Started Making " + pluralString + " ...");
259

    
260
			initPreparedStatements(state);
261
			
262
			// Stores whether this invoke was successful or not.
263
			boolean success = true;
264
	
265
			// PESI: Clear the database table Taxon.
266
			doDelete(state);
267
			
268
			// Get specific mappings: (CDM) Taxon -> (PESI) Taxon
269
			PesiExportMapping mapping = getMapping();
270
	
271
			// Initialize the db mapper
272
			mapping.initialize(state);
273

    
274
			// Find extensionTypes
275
			lastActionExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionUuid);
276
			lastActionDateExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionDateUuid);
277
			expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
278
			speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
279
			cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.cacheCitationUuid);
280
			expertUserIdExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertUserIdUuid);
281
			speciesExpertUserIdExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertUserIdUuid);
282

    
283
			//"PHASE 5: Handle names without taxa ...
284
			success &= doNames(state);
285

    
286
			
287
			//Export Taxa..
288
			success &= doPhase01(state, mapping);
289

    
290
			// 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
291
			success &= doPhase02(state);
292

    
293
			//PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
294
			success &= doPhase03(state);
295
			
296
			//"PHASE 4: Creating Inferred Synonyms...
297
			success &= doPhase04(state, mapping);
298
			
299
			
300
			logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
301

    
302
			if (!success){
303
				state.setUnsuccessfull();
304
			}
305
			return;
306
		} catch (SQLException e) {
307
			e.printStackTrace();
308
			logger.error(e.getMessage());
309
			state.setUnsuccessfull();
310
			return;
311
		}
312
	}
313

    
314
	private void initPreparedStatements(PesiExportState state) throws SQLException {
315
		initTreeIndexStatement(state);
316
		initRankExpertsUpdateStmt(state);
317
		initRankUpdateStatement(state);
318
	}
319

    
320
	// Prepare TreeIndex-And-KingdomFk-Statement
321
	private void initTreeIndexStatement(PesiExportState state) throws SQLException {
322
		Connection connection = state.getConfig().getDestination().getConnection();
323
		String parentTaxonFk_TreeIndex_KingdomFkSql = "UPDATE Taxon SET ParentTaxonFk = ?, TreeIndex = ? WHERE TaxonId = ?"; 
324
		parentTaxonFk_TreeIndex_KingdomFkStmt = connection.prepareStatement(parentTaxonFk_TreeIndex_KingdomFkSql);
325
	}
326

    
327
	private void initRankUpdateStatement(PesiExportState state) throws SQLException {
328
		Connection connection = state.getConfig().getDestination().getConnection();
329
		String rankSql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, KingdomFk = ? WHERE TaxonId = ?";
330
		rankUpdateStmt = connection.prepareStatement(rankSql);
331
	}
332

    
333
	private void initRankExpertsUpdateStmt(PesiExportState state) throws SQLException {
334
//		String sql_old = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ?, " +
335
//				"ExpertFk = ?, SpeciesExpertFk = ? WHERE TaxonId = ?";
336
		//TODO handle experts GUIDs
337
		Connection connection = state.getConfig().getDestination().getConnection();
338
		
339
		String sql = "UPDATE Taxon SET RankFk = ?, RankCache = ?, TypeNameFk = ?, KingdomFk = ? " +
340
				" WHERE TaxonId = ?";
341
		rankTypeExpertsUpdateStmt = connection.prepareStatement(sql);
342
	}
343

    
344
	private boolean doPhase01(PesiExportState state, PesiExportMapping mapping) throws SQLException {
345
		int count = 0;
346
		int pastCount = 0;
347
		List<TaxonBase> list;
348
		boolean success = true;
349
		// Get the limit for objects to save within a single transaction.
350
		int limit = state.getConfig().getLimitSave();
351

    
352
		
353
		logger.info("PHASE 1: Export Taxa...");
354
		// Start transaction
355
		TransactionStatus txStatus = startTransaction(true);
356
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
357
		
358
		
359
		int partitionCount = 0;
360
		while ((list = getNextTaxonPartition(null, limit, partitionCount++)).size() > 0   ) {
361

    
362
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
363
			for (TaxonBase<?> taxon : list) {
364
				doCount(count++, modCount, pluralString);
365
				success &= mapping.invoke(taxon);
366
				
367
				TaxonNameBase<?,?> taxonName = taxon.getName();
368

    
369
				validatePhaseOne(taxon, taxonName);
370
				
371
			}
372

    
373
			// Commit transaction
374
			commitTransaction(txStatus);
375
			logger.debug("Committed transaction.");
376
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
377
			pastCount = count;
378

    
379
			// Start transaction
380
			txStatus = startTransaction(true);
381
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
382
		}
383
		if (list.size() == 0) {
384
			logger.info("No " + pluralString + " left to fetch.");
385
		}
386
		// Commit transaction
387
		commitTransaction(txStatus);
388
		logger.debug("Committed transaction.");
389
		return success;
390
	}
391

    
392

    
393
	private void validatePhaseOne(TaxonBase<?> taxon, TaxonNameBase<?, ?> taxonName) {
394
		// Check whether some rules are violated
395
		nomenclaturalCode = taxonName.getNomenclaturalCode();
396
		if (! taxonName.isInstanceOf(NonViralName.class)){
397
			logger.warn("Viral names can't be validated");
398
		}
399
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
400
		String genusOrUninomial = nvn.getGenusOrUninomial();
401
		String specificEpithet = nvn.getSpecificEpithet();
402
		String infraSpecificEpithet = nvn.getInfraSpecificEpithet();
403
		String infraGenericEpithet = nvn.getInfraGenericEpithet();
404
		Integer rank = getRankFk(taxonName, nomenclaturalCode);
405
		
406
		if (rank == null) {
407
			logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
408
		} else {
409
			
410
			// Check whether infraGenericEpithet is set correctly
411
			// 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
412
			// 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
413
			
414
			int ancestorLevel = 0;
415
			if (taxonName.getRank().equals(Rank.SUBSPECIES())) {
416
				// The accepted taxon two rank levels above should be of rank subgenus
417
				ancestorLevel  = 2;
418
			}
419
			if (taxonName.getRank().equals(Rank.SPECIES())) {
420
				// The accepted taxon one rank level above should be of rank subgenus
421
				ancestorLevel = 1;
422
			}
423
			if (ancestorLevel > 0) {
424
				if (ancestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {
425
					// The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
426
					if (infraGenericEpithet == null) {
427
						logger.warn("InfraGenericEpithet does not exist even though it should for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
428
						// maybe the taxon could be named here
429
					}
430
				}
431
			}
432
			
433
			if (infraGenericEpithet == null && rank.intValue() == 190) {
434
				logger.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
435
			}
436
			if (specificEpithet != null && rank.intValue() < 216) {
437
				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() + ")");
438
			}
439
			if (infraSpecificEpithet != null && rank.intValue() < 225) {
440
				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() + ")"; 
441
				if (StringUtils.isNotBlank(infraSpecificEpithet)){
442
					logger.warn(message);
443
				}else{
444
					logger.warn(message);
445
				}
446
			}
447
		}
448
		if (infraSpecificEpithet != null && specificEpithet == null) {
449
			logger.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: "  + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
450
		}
451
		if (genusOrUninomial == null) {
452
			logger.warn("GenusOrUninomial was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
453
		}
454
	}
455

    
456
	// 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
457
	private boolean doPhase02(PesiExportState state) {
458
		boolean success = true;
459
		List<Classification> classificationList = null;
460
		logger.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
461
		
462
		// Specify starting ranks for tree traversing
463
		rankList.add(Rank.KINGDOM());
464
		rankList.add(Rank.GENUS());
465

    
466
		// Specify where to stop traversing (value) when starting at a specific Rank (key)
467
		rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
468
		rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
469
		
470
		StringBuffer treeIndex = new StringBuffer();
471
		
472
		// Retrieve list of classifications
473
		TransactionStatus txStatus = startTransaction(true);
474
		logger.info("Started transaction. Fetching all classifications...");
475
		classificationList = getClassificationService().listClassifications(null, 0, null, null);
476
		commitTransaction(txStatus);
477
		logger.debug("Committed transaction.");
478

    
479
		logger.info("Fetched " + classificationList.size() + " classification(s).");
480

    
481
		setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex, "TreeIndex", "", "TI"));
482
		
483
		for (Classification classification : classificationList) {
484
			for (Rank rank : rankList) {
485
				
486
				txStatus = startTransaction(true);
487
				logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
488

    
489
				List<TaxonNode> rankSpecificRootNodes = getClassificationService().loadRankSpecificRootNodes(classification, rank, null);
490
				logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
491

    
492
				commitTransaction(txStatus);
493
				logger.debug("Committed transaction.");
494

    
495
				for (TaxonNode rootNode : rankSpecificRootNodes) {
496
					txStatus = startTransaction(false);
497
					Rank endRank = rank2endRankMap.get(rank);
498
					if (endRank != null) {
499
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");
500
					} else {
501
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");
502
					}
503

    
504
					TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
505

    
506
					if (isPesiTaxon(newNode.getTaxon())){
507
						TaxonNode parentNode = newNode.getParent();
508
						if (rank.equals(Rank.KINGDOM())) {
509
							treeIndex = new StringBuffer();
510
							treeIndex.append("#");
511
						} else {
512
							// Get treeIndex from parentNode
513
							if (parentNode != null) {
514
								boolean annotationFound = false;
515
								Set<Annotation> annotations = parentNode.getAnnotations();
516
								for (Annotation annotation : annotations) {
517
									AnnotationType annotationType = annotation.getAnnotationType();
518
									if (annotationType != null && annotationType.equals(getTreeIndexAnnotationType())) {
519
										treeIndex = new StringBuffer(CdmUtils.Nz(annotation.getText()));
520
										annotationFound = true;
521
	//									logger.error("treeIndex: " + treeIndex);
522
										break;
523
									}
524
								}
525
								if (!annotationFound) {
526
									// This should not happen because it means that the treeIndex was not set correctly as an annotation to parentNode
527
									logger.error("TreeIndex could not be read from annotation of TaxonNode: " + parentNode.getUuid() + ", Taxon: " + parentNode.getTaxon().getUuid());
528
									treeIndex = new StringBuffer();
529
									treeIndex.append("#");
530
								}
531
							} else {
532
								// TreeIndex could not be determined, but it's unclear how to proceed to generate a correct treeIndex if the parentNode is NULL
533
								logger.error("ParentNode for RootNode is NULL. TreeIndex could not be determined: " + newNode.getUuid());
534
								treeIndex = new StringBuffer(); // This just prevents growing of the treeIndex in a wrong manner
535
								treeIndex.append("#");
536
							}
537
						}
538
						nomenclaturalCode = newNode.getTaxon().getName().getNomenclaturalCode();
539
						kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
540
						traverseTree(newNode, parentNode, treeIndex, endRank, state);
541
					}else{
542
						logger.debug("Taxon is not a PESI taxon: " + newNode.getTaxon().getUuid());
543
					}
544
					
545
					
546
					
547
					commitTransaction(txStatus);
548
					logger.debug("Committed transaction.");
549

    
550
				}
551
			}
552
		}
553
		return success;
554
	}	
555

    
556
	//PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
557
	private boolean doPhase03(PesiExportState state) {
558
		int count = 0;
559
		int pastCount = 0;
560
		boolean success = true;
561
		// Get the limit for objects to save within a single transaction.
562
		int limit = state.getConfig().getLimitSave();
563

    
564
		List<TaxonBase> list;
565
		logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
566
		// Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
567
		
568
		// Start transaction
569
		TransactionStatus txStatus = startTransaction(true);
570
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
571
		int partitionCount = 0;
572
		while ((list = getNextTaxonPartition(null, limit, partitionCount++)).size() > 0) {
573

    
574
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
575
			for (TaxonBase<?> taxon : list) {
576
				TaxonNameBase<?,?> taxonName = taxon.getName();
577
				// Determine expertFk
578
				Integer expertFk = makeExpertFk(state, taxonName);
579

    
580
				// Determine speciesExpertFk
581
				Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
582

    
583
				doCount(count++, modCount, pluralString);
584
				Integer typeNameFk = getTypeNameFk(taxonName, state);
585
				
586
				//TODO why are expertFks needed? (Andreas M.)
587
//				if (expertFk != null || speciesExpertFk != null) {
588
					invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon), 
589
							typeNameFk, kingdomFk, expertFk, speciesExpertFk);
590
//				}
591
			}
592

    
593
			// Commit transaction
594
			commitTransaction(txStatus);
595
			logger.debug("Committed transaction.");
596
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
597
			pastCount = count;
598

    
599
			// Start transaction
600
			txStatus = startTransaction(true);
601
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
602
		}
603
		if (list.size() == 0) {
604
			logger.info("No " + pluralString + " left to fetch.");
605
		}
606
		// Commit transaction
607
		commitTransaction(txStatus);
608
		logger.debug("Committed transaction.");
609
		return success;
610
	}
611

    
612
	private Integer makeSpeciesExpertFk(PesiExportState state, TaxonNameBase<?, ?> taxonName) {
613
		List<Reference> referenceList;
614
		Integer speciesExpertFk = null;
615
		String speciesExpertUserId = getSpeciesExpertUserId(taxonName);
616
		if (speciesExpertUserId != null) {
617
			
618
			// The speciesExpertUserId was stored in the field 'title' of the corresponding Reference during FaEu import
619
			referenceList = getReferenceService().listByReferenceTitle(null, speciesExpertUserId, MatchMode.EXACT, null, null, null, null, null);
620
			if (referenceList.size() == 1) {
621
				speciesExpertFk  = getSpeciesExpertFk(referenceList.iterator().next(), state);
622
			} else if (referenceList.size() > 1) {
623
				logger.error("Found more than one match using listByTitle() searching for a Reference with this speciesExpertUserId as title: " + speciesExpertUserId);
624
			} else if (referenceList.size() == 0) {
625
				logger.error("Found no match using listByReferenceTitle() searching for a Reference with this speciesExpertUserId as title: " + speciesExpertUserId);
626
			}
627
		} else {
628
			logger.debug("SpeciesExpertName is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
629
		}
630
		return speciesExpertFk;
631
	}
632

    
633
	private Integer makeExpertFk(PesiExportState state,
634
			TaxonNameBase<?, ?> taxonName) {
635
		List<Reference> referenceList;
636
		Integer expertFk = null;
637
		String expertUserId = getExpertUserId(taxonName);
638
		if (expertUserId != null) {
639

    
640
			// The expertUserId was stored in the field 'title' of the corresponding Reference during FaEu import
641
			referenceList = getReferenceService().listByReferenceTitle(null, expertUserId, MatchMode.EXACT, null, null, null, null, null);
642
			if (referenceList.size() == 1) {
643
				expertFk  = getExpertFk(referenceList.iterator().next(), state);
644
			} else if (referenceList.size() > 1) {
645
				logger.error("Found more than one match using listByReferenceTitle() searching for a Reference with this expertUserId as title: " + expertUserId);
646
			} else if (referenceList.size() == 0) {
647
				logger.error("Found no match using listByReferenceTitle() searching for a Reference with this expertUserId as title: " + expertUserId);
648
			}
649
		} else {
650
			logger.debug("ExpertName is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
651
		}
652
		return expertFk;
653
	}
654
	
655
	//	"PHASE 4: Creating Inferred Synonyms..."
656
	private boolean doPhase04(PesiExportState state, PesiExportMapping mapping) throws SQLException {
657
		int count;
658
		int pastCount;
659
		boolean success = true;
660
		// Get the limit for objects to save within a single transaction.
661
		int limit = state.getConfig().getLimitSave();
662

    
663
		// Create inferred synonyms for accepted taxa
664
		logger.info("PHASE 4: Creating Inferred Synonyms...");
665

    
666
		// Determine the count of elements in datawarehouse database table Taxon
667
		Integer currentTaxonId = determineTaxonCount(state);
668
		currentTaxonId++;
669

    
670
		count = 0;
671
		pastCount = 0;
672
		int pageSize = limit;
673
		int pageNumber = 1;
674
		String inferredSynonymPluralString = "Inferred Synonyms";
675
		
676
		// Start transaction
677
		Classification classification = null;
678
		Taxon acceptedTaxon = null;
679
		TransactionStatus txStatus = startTransaction(true);
680
		logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
681
		List<TaxonBase> taxonList = null;
682
		List<Synonym> inferredSynonyms = null;
683
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", null, pageSize, pageNumber)).size() > 0) {
684
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
685

    
686
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
687
			for (TaxonBase<?> taxonBase : taxonList) {
688

    
689
				if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
690
					acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
691
					TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
692
					
693
					if (taxonName.isInstanceOf(ZoologicalName.class)) {
694
						nomenclaturalCode  = taxonName.getNomenclaturalCode();
695
						kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
696

    
697
						Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();
698
						TaxonNode singleNode = null;
699
						if (taxonNodes.size() > 0) {
700
							// Determine the classification of the current TaxonNode
701
							singleNode = taxonNodes.iterator().next();
702
							if (singleNode != null) {
703
								classification = singleNode.getClassification();
704
							} else {
705
								logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");
706
							}
707
						} else {
708
							// Classification could not be determined directly from this TaxonNode
709
							// The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
710
							if (classification == null) {
711
								logger.error("Classification could not be determined directly from this TaxonNode: " + singleNode.getUuid() + "). " +
712
										"This classification stored from another TaxonNode is used: " + classification.getTitleCache());
713
							}
714
						}
715
						
716
						if (classification != null) {
717
							inferredSynonyms  = getTaxonService().createAllInferredSynonyms(classification, acceptedTaxon);
718

    
719
//								inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymRelationshipType.INFERRED_GENUS_OF());
720
							if (inferredSynonyms != null) {
721
								for (Synonym synonym : inferredSynonyms) {
722
									TaxonNameBase<?,?> synonymName = synonym.getName();
723
									if (synonymName != null) {
724
										
725
										// Both Synonym and its TaxonName have no valid Id yet
726
										synonym.setId(currentTaxonId++);
727
										synonymName.setId(currentTaxonId++);
728
										
729
										doCount(count++, modCount, inferredSynonymPluralString);
730
										success &= mapping.invoke(synonymName);
731
										
732
										// Add Rank Data and KingdomFk to hashmap for later saving
733
										inferredSynonymsDataToBeSaved.put(synonymName.getId(), synonymName);
734
									} else {
735
										logger.error("TaxonName of this Synonym is NULL: " + synonym.getUuid() + " (" + synonym.getTitleCache() + ")");
736
									}
737
								}
738
							}
739
						} else {
740
							logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");
741
						}
742
					} else {
743
//							logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
744
					}
745
				} else {
746
					logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");
747
				}
748
			}
749

    
750
			// Commit transaction
751
			commitTransaction(txStatus);
752
			logger.debug("Committed transaction.");
753
			logger.info("Exported " + (count - pastCount) + " " + inferredSynonymPluralString + ". Total: " + count);
754
			pastCount = count;
755
			
756
			// Save Rank Data and KingdomFk for inferred synonyms
757
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
758
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk);
759
			}
760

    
761
			// Start transaction
762
			txStatus = startTransaction(true);
763
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
764
			
765
			// Increment pageNumber
766
			pageNumber++;
767
		}
768
		if (taxonList.size() == 0) {
769
			logger.info("No " + parentPluralString + " left to fetch.");
770
		}
771
		// Commit transaction
772
		commitTransaction(txStatus);
773
		logger.debug("Committed transaction.");
774
		return success;
775
	}
776
	
777

    
778
	/**
779
	 * Handles names that do not appear in taxa
780
	 * @param state
781
	 * @param mapping
782
	 * @return
783
	 */
784
	private boolean doNames(PesiExportState state)  throws SQLException {
785
		
786
		boolean success;
787
		try {
788
			PesiExportMapping mapping = getNameMapping();
789
			mapping.initialize(state);
790
			int count = 0;
791
			int pastCount = 0;
792
			List<NonViralName<?>> list;
793
			success = true;
794
			// Get the limit for objects to save within a single transaction.
795
			int limit = state.getConfig().getLimitSave();
796

    
797
			
798
			logger.info("PHASE 5: Export Pure Names ...");
799
			// Start transaction
800
			TransactionStatus txStatus = startTransaction(true);
801
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
802
			
803
			
804
			int partitionCount = 0;
805
			while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {
806

    
807
				logger.info("Fetched " + list.size() + " names without taxa. Exporting...");
808
				for (NonViralName<?> taxonName : list) {
809
					doCount(count++, modCount, pluralString);
810
					success &= mapping.invoke(taxonName);
811
				}
812

    
813
				// Commit transaction
814
				commitTransaction(txStatus);
815
				logger.debug("Committed transaction.");
816
				logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
817
				pastCount = count;
818

    
819
				// Start transaction
820
				txStatus = startTransaction(true);
821
				logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
822
			}
823
			if (list == null) {
824
				logger.info("No " + pluralString + " left to fetch.");
825
			}
826
			// Commit transaction
827
			commitTransaction(txStatus);
828
			logger.debug("Committed transaction.");
829
		} catch (Exception e) {
830
			logger.error("Error occurred in pure name export");
831
			e.printStackTrace();
832
			success = false;
833
		}
834
		return success;
835
	}
836

    
837
	/**
838
	 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
839
	 * @param state The {@link PesiExportState PesiExportState}.
840
	 * @return The count.
841
	 */
842
	private Integer determineTaxonCount(PesiExportState state) {
843
		Integer result = null;
844
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
845
		
846
		String sql;
847
		Source destination =  pesiConfig.getDestination();
848
		sql = "SELECT COUNT(*) FROM Taxon";
849
		destination.setQuery(sql);
850
		ResultSet resultSet = destination.getResultSet();
851
		try {
852
			resultSet.next();
853
			result = resultSet.getInt(1);
854
		} catch (SQLException e) {
855
			logger.error("TaxonCount could not be determined: " + e.getMessage());
856
			e.printStackTrace();
857
		}
858
		return result;
859
	}
860

    
861
	/**
862
	 * Returns the userId of the expert associated with the given TaxonName.
863
	 * @param taxonName A {@link TaxonNameBase TaxonName}.
864
	 * @return The userId.
865
	 */
866
	private String getExpertUserId(TaxonNameBase<?,?> taxonName) {
867
		String result = null;
868
		try {
869
			Set<Extension> extensions = taxonName.getExtensions();
870
			for (Extension extension : extensions) {
871
				if (extension.getType().equals(expertUserIdExtensionType)) {
872
					result = extension.getValue();
873
				}
874
			}
875
		} catch (Exception e) {
876
			e.printStackTrace();
877
		}
878
		return result;
879
	}
880

    
881
	/**
882
	 * Returns the userId of the speciesExpert associated with the given TaxonName.
883
	 * @param taxonName A {@link TaxonNameBase TaxonName}.
884
	 * @return The userId.
885
	 */
886
	private String getSpeciesExpertUserId(TaxonNameBase<?,?> taxonName) {
887
		String result = null;
888
		try {
889
			Set<Extension> extensions = taxonName.getExtensions();
890
			for (Extension extension : extensions) {
891
				if (extension.getType().equals(speciesExpertUserIdExtensionType)) {
892
					result = extension.getValue();
893
				}
894
			}
895
		} catch (Exception e) {
896
			e.printStackTrace();
897
		}
898
		return result;
899
	}
900
	
901
	/**
902
	 * Checks whether a parent at specific level has a specific Rank.
903
	 * @param taxonName A {@link TaxonNameBase TaxonName}.
904
	 * @param level The ancestor level.
905
	 * @param ancestorRank The ancestor rank.
906
	 * @return Whether a parent at a specific level has a specific Rank.
907
	 */
908
	private boolean ancestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {
909
		boolean result = false;
910
		TaxonNode parentNode = null;
911
		if (taxonBase.isInstanceOf(Taxon.class)){
912
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
913
			// Get ancestor Taxon via TaxonNode
914
			Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
915
			if (taxonNodes.size() == 1) {
916
				TaxonNode taxonNode = taxonNodes.iterator().next();
917
				if (taxonNode != null) {
918
					for (int i = 0; i < level; i++) {
919
						if (taxonNode != null) {
920
							taxonNode  = taxonNode.getParent();
921
						}
922
					}
923
					parentNode = taxonNode;
924
				}
925
			} else if (taxonNodes.size() > 1) {
926
				logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
927
			}
928
		}
929
		//compare
930
		if (parentNode != null) {
931
			TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);
932
			Taxon parentTaxon = node.getTaxon();
933
			if (parentTaxon != null) {
934
				TaxonNameBase<?,?> parentTaxonName = parentTaxon.getName();
935
				if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {
936
					result = true;
937
				}
938
			} else {
939
				logger.error("This TaxonNode has no Taxon: " + node.getUuid());
940
			}
941
		}
942
		return result;
943
	}
944

    
945
	/**
946
	 * Returns the AnnotationType for a given UUID.
947
	 * @param uuid The Annotation UUID.
948
	 * @param label The Annotation label.
949
	 * @param text The Annotation text.
950
	 * @param labelAbbrev The Annotation label abbreviation.
951
	 * @return The AnnotationType.
952
	 */
953
	protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){
954
		AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);
955
		if (annotationType == null) {
956
			annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
957
			annotationType.setUuid(uuid);
958
//			annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
959
			getTermService().save(annotationType);
960
		}
961
		return annotationType;
962
	}
963

    
964
	/**
965
	 * Traverses the classification recursively and stores determined values for every Taxon.
966
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
967
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
968
	 * @param treeIndex The TreeIndex at the current level.
969
	 * @param fetchLevel Rank to stop fetching at.
970
	 * @param state The {@link PesiExportState PesiExportState}.
971
	 */
972
	private void traverseTree(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, Rank fetchLevel, PesiExportState state) {
973
		// Traverse all branches from this childNode until specified fetchLevel is reached.
974
		StringBuffer localTreeIndex = new StringBuffer(treeIndex);
975
		Taxon childTaxon = childNode.getTaxon();
976
		if (childTaxon != null) {
977
			if (isPesiTaxon(childTaxon)){
978
				Integer taxonId = state.getDbId(childTaxon);
979
				TaxonNameBase<?,?> childName = childTaxon.getName();
980
				if (taxonId != null) {
981
					Rank childRank = childName.getRank();
982
					if (childRank != null) {
983
						if (! childRank.equals(fetchLevel)) {
984
	
985
							localTreeIndex.append(taxonId + "#");
986
							
987
							saveData(childNode, parentNode, localTreeIndex, state, taxonId);
988
	
989
							// Store treeIndex as annotation for further use
990
							Annotation annotation = Annotation.NewInstance(localTreeIndex.toString(), getTreeIndexAnnotationType(), Language.DEFAULT());
991
							childNode.addAnnotation(annotation);
992
	
993
							for (TaxonNode newNode : childNode.getChildNodes()) {
994
								if (newNode.getTaxon() != null && isPesiTaxon(newNode.getTaxon())){
995
									traverseTree(newNode, childNode, localTreeIndex, fetchLevel, state);
996
								}
997
							}
998
							
999
						} else {
1000
	//						logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1001
							return;
1002
						}
1003
					} else {
1004
						logger.error("Rank is NULL. FetchLevel can not be checked: " + childName.getUuid() + " (" + childName.getTitleCache() + ")");
1005
					}
1006
				} else {
1007
					logger.error("Taxon can not be found in state: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
1008
				}
1009
			}else{
1010
				if (logger.isDebugEnabled()){ 
1011
					logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
1012
				}
1013
			}
1014

    
1015
		} else {
1016
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
1017
		}
1018
	}
1019

    
1020
	/**
1021
	 * Stores values in database for every recursive round.
1022
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1023
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1024
	 * @param treeIndex The TreeIndex at the current level.
1025
	 * @param state The {@link PesiExportState PesiExportState}.
1026
	 * @param currentTaxonFk The TaxonFk to store the values for.
1027
	 */
1028
	private void saveData(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, PesiExportState state, Integer currentTaxonFk) {
1029
		// We are differentiating kingdoms by the nomenclatural code for now.
1030
		// This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1031
		Taxon childTaxon = childNode.getTaxon();
1032
		if (isPesiTaxon(childTaxon)) {
1033
			TaxonBase<?> parentTaxon = null;
1034
			if (parentNode != null) {
1035
				parentTaxon = parentNode.getTaxon();
1036
				
1037
			}
1038

    
1039
			invokeParentTaxonFkAndTreeIndex(state.getDbId(parentTaxon), currentTaxonFk,	treeIndex);
1040
		}
1041
		
1042
	}
1043

    
1044
	/**
1045
	 * Inserts values into the Taxon database table.
1046
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1047
	 * @param state The {@link PesiExportState PesiExportState}.
1048
	 * @param stmt The prepared statement.
1049
	 * @return Whether save was successful or not.
1050
	 */
1051
	protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk, Integer currentTaxonFk, StringBuffer treeIndex) {
1052
		try {
1053
			if (parentTaxonFk != null) {
1054
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(1, parentTaxonFk);
1055
			} else {
1056
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(1, null);
1057
			}
1058

    
1059
			if (treeIndex != null) {
1060
				parentTaxonFk_TreeIndex_KingdomFkStmt.setString(2, treeIndex.toString());
1061
			} else {
1062
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(2, null);
1063
			}
1064

    
1065
			if (currentTaxonFk != null) {
1066
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(3, currentTaxonFk);
1067
			} else {
1068
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(3, null);
1069
			}
1070
			
1071
			parentTaxonFk_TreeIndex_KingdomFkStmt.executeUpdate();
1072
			return true;
1073
		} catch (SQLException e) {
1074
			logger.error("ParentTaxonFk (" + parentTaxonFk ==null? "-":parentTaxonFk + ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk == null? "-" :currentTaxonFk) + ": " + e.getMessage());
1075
			e.printStackTrace();
1076
			return false;
1077
		}
1078
	}
1079

    
1080
	/**
1081
	 * Inserts Rank data and KingdomFk into the Taxon database table.
1082
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1083
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1084
	 * @param taxonFk The TaxonFk to store the values for.
1085
	 * @param kindomFk The KingdomFk.
1086
	 * @return Whether save was successful or not.
1087
	 */
1088
	private boolean invokeRankDataAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, 
1089
			Integer taxonFk, Integer kingdomFk) {
1090
		try {
1091
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1092
			if (rankFk != null) {
1093
				rankUpdateStmt.setInt(1, rankFk);
1094
			} else {
1095
				rankUpdateStmt.setObject(1, null);
1096
			}
1097
	
1098
			String rankCache = getRankCache(taxonName, nomenclaturalCode);
1099
			if (rankCache != null) {
1100
				rankUpdateStmt.setString(2, rankCache);
1101
			} else {
1102
				rankUpdateStmt.setObject(2, null);
1103
			}
1104
			
1105
			if (kingdomFk != null) {
1106
				rankUpdateStmt.setInt(3, kingdomFk);
1107
			} else {
1108
				rankUpdateStmt.setObject(3, null);
1109
			}
1110
			
1111
			if (taxonFk != null) {
1112
				rankUpdateStmt.setInt(4, taxonFk);
1113
			} else {
1114
				rankUpdateStmt.setObject(4, null);
1115
			}
1116
			
1117
			rankUpdateStmt.executeUpdate();
1118
			return true;
1119
		} catch (SQLException e) {
1120
			logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());
1121
			e.printStackTrace();
1122
			return false;
1123
		}
1124
	}
1125

    
1126
	/**
1127
	 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1128
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1129
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1130
	 * @param taxonFk The TaxonFk to store the values for.
1131
	 * @param typeNameFk The TypeNameFk.
1132
	 * @param kindomFk The KingdomFk.
1133
	 * @param expertFk The ExpertFk.
1134
	 * @param speciesExpertFk The SpeciesExpertFk.
1135
	 * @return Whether save was successful or not.
1136
	 */
1137
	private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, 
1138
			Integer taxonFk, Integer typeNameFk, Integer kingdomFk,
1139
			Integer expertFk, Integer speciesExpertFk) {
1140
		try {
1141
			int index = 1;
1142
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1143
			if (rankFk != null) {
1144
				rankTypeExpertsUpdateStmt.setInt(index++, rankFk);
1145
			} else {
1146
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1147
			}
1148
	
1149
			String rankCache = getRankCache(taxonName, nomenclaturalCode);
1150
			if (rankCache != null) {
1151
				rankTypeExpertsUpdateStmt.setString(index++, rankCache);
1152
			} else {
1153
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1154
			}
1155
			
1156
			if (typeNameFk != null) {
1157
				rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);
1158
			} else {
1159
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1160
			}
1161
			
1162
			if (kingdomFk != null) {
1163
				rankTypeExpertsUpdateStmt.setInt(index++, kingdomFk);
1164
			} else {
1165
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1166
			}
1167
			
1168
//			if (expertFk != null) {
1169
//				rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1170
//			} else {
1171
//				rankTypeExpertsUpdateStmt.setObject(5, null);
1172
//			}
1173
//
1174
//			//TODO handle experts GUIDS
1175
//			if (speciesExpertFk != null) {
1176
//				rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1177
//			} else {
1178
//				rankTypeExpertsUpdateStmt.setObject(6, null);
1179
//			}
1180
//			
1181
			if (taxonFk != null) {
1182
				rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);
1183
			} else {
1184
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1185
			}
1186

    
1187
			rankTypeExpertsUpdateStmt.executeUpdate();
1188
			return true;
1189
		} catch (SQLException e) {
1190
			logger.error("Data could not be inserted into database: " + e.getMessage());
1191
			e.printStackTrace();
1192
			return false;
1193
		}
1194
	}
1195

    
1196
	/**
1197
	 * Deletes all entries of database tables related to <code>Taxon</code>.
1198
	 * @param state The {@link PesiExportState PesiExportState}.
1199
	 * @return Whether the delete operation was successful or not.
1200
	 */
1201
	protected boolean doDelete(PesiExportState state) {
1202
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
1203
		
1204
		String sql;
1205
		Source destination =  pesiConfig.getDestination();
1206

    
1207
		// Clear Taxon
1208
		sql = "DELETE FROM " + dbTableName;
1209
		destination.setQuery(sql);
1210
		destination.update(sql);
1211
		return true;
1212
	}
1213

    
1214
	/* (non-Javadoc)
1215
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1216
	 */
1217
	@Override
1218
	protected boolean isIgnore(PesiExportState state) {
1219
		return ! state.getConfig().isDoTaxa();
1220
	}
1221

    
1222
	/**
1223
	 * Returns the <code>RankFk</code> attribute.
1224
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1225
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1226
	 * @return The <code>RankFk</code> attribute.
1227
	 * @see MethodMapper
1228
	 */
1229
	private static Integer getRankFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1230
		Integer result = null;
1231
		try {
1232
		if (nomenclaturalCode != null) {
1233
			if (taxonName != null) {
1234
				if (taxonName.getRank() == null) {
1235
					logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1236
				} else {
1237
					result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1238
				}
1239
				if (result == null) {
1240
					logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1241
				}
1242
			}
1243
		}
1244
		} catch (Exception e) {
1245
			e.printStackTrace();
1246
		}
1247
		return result;
1248
	}
1249

    
1250
	/**
1251
	 * Returns the <code>RankCache</code> attribute.
1252
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1253
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1254
	 * @return The <code>RankCache</code> attribute.
1255
	 * @see MethodMapper
1256
	 */
1257
	private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1258
		String result = null;
1259
		try {
1260
		if (nomenclaturalCode != null) {
1261
			result = PesiTransformer.rank2RankCache(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1262
		}
1263
		} catch (Exception e) {
1264
			e.printStackTrace();
1265
		}
1266
		return result;
1267
	}
1268

    
1269
	
1270
	/**
1271
	 * Returns the <code>WebShowName</code> attribute.
1272
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1273
	 * @return The <code>WebShowName</code> attribute.
1274
	 * @see MethodMapper
1275
	 */
1276
	private static String getWebShowName(TaxonNameBase<?,?> taxonName) {
1277
		String result = "";
1278
		
1279
		try {
1280
			List<TaggedText> taggedName = taxonName.getTaggedName();
1281
			boolean openTag = false;
1282
			boolean start = true;
1283
			for (TaggedText taggedText : taggedName) {
1284
				if (taggedText.isName() || taggedText.isHybridSign()  ) {
1285
					// Name
1286
					if (! openTag) {
1287
						if (start) {
1288
							result = "<i>";
1289
							start = false;
1290
						} else {
1291
							result += " <i>";
1292
						}
1293
						openTag = true;
1294
					} else {
1295
						result += " ";
1296
					}
1297
					result += taggedText.getText();
1298
				} else if (taggedText.isSeparator()) {
1299
					//Separator
1300
					if (! openTag) {
1301
						logger.warn("Semantics of separator outside name not yet defined: "+ taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1302
					}
1303
					result += taggedText.getText();
1304
				} else if (taggedText.isRank()) {
1305
					// Rank
1306
					String rankAbbrev = taggedText.getText();
1307
					
1308
					if (StringUtils.isBlank(rankAbbrev)) {
1309
						logger.error("Rank abbreviation is an empty string: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1310
					} else {
1311
						if (openTag) {
1312
							result += "</i> ";
1313
							openTag = false;
1314
						} else {
1315
							result += " ";
1316
						}
1317
						result +=rankAbbrev;
1318
					}
1319
				} else if (taggedText.isAuthors()) {
1320
					//Team
1321
					if (openTag) {
1322
						result += "</i> ";
1323
						openTag = false;
1324
					} else {
1325
						result += " ";
1326
					}
1327
					result += taggedText.getText();
1328
				} else if (taggedText.isYear()) {
1329
					if (openTag) {
1330
						result += "</i> ";
1331
						openTag = false;
1332
					} else {
1333
						result += " ";
1334
					}
1335
					result += taggedText.getText();
1336
				} else if (taggedText.isReference()) {
1337
					if (openTag) {
1338
						result += "</i> ";
1339
						openTag = false;
1340
					} else {
1341
						result += " ";
1342
					}
1343
					result += taggedText.getText();
1344
				} else {
1345
					if (taggedText.getText() == null) {
1346
						logger.warn("TaggedName for " + taggedText.getType() +" is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1347
					} else {
1348
						logger.error("TaggedText typ is unknown. Tag type: " + taggedText.getType() + ", TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1349
					}
1350
				}
1351
			}
1352
			if (openTag) {
1353
				result += "</i>";
1354
			}
1355
		} catch (Exception e) {
1356
			e.printStackTrace();
1357
		}
1358

    
1359
		return result;
1360
	}
1361

    
1362
	/**
1363
	 * Returns the <code>AuthorString</code> attribute.
1364
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1365
	 * @return The <code>AuthorString</code> attribute.
1366
	 * @see MethodMapper
1367
	 */
1368
	@SuppressWarnings("unused")
1369
	private static String getAuthorString(TaxonBase<?> taxon) {
1370
		String result = null;
1371
		try {
1372
			boolean isNonViralName = false;
1373
			String authorshipCache = null;
1374
			TaxonNameBase<?,?> taxonName = taxon.getName();
1375
			if (taxonName != null && taxonName.isInstanceOf(NonViralName.class)){
1376
				authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();
1377
				isNonViralName = true;
1378
			}
1379
			// For a misapplied name without an authorshipCache the authorString should be set to "auct."
1380
			if (isMisappliedName(taxon) && authorshipCache == null) {
1381
				// Set authorshipCache to "auct."
1382
				result = PesiTransformer.auctString;
1383
			}else{
1384
				result = authorshipCache;
1385
			}
1386
			if (taxonName == null){
1387
				logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1388
			}else if (! isNonViralName){
1389
				logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1390
			}
1391
			
1392
		} catch (Exception e) {
1393
			e.printStackTrace();
1394
		}
1395
		
1396
		if (StringUtils.isBlank(result)) {
1397
			return null;
1398
		} else {
1399
			return result;
1400
		}
1401
	}
1402

    
1403
	
1404
	/**
1405
	 * Checks whether a given TaxonName is a misapplied name.
1406
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1407
	 * @return Whether the given TaxonName is a misapplied name or not.
1408
	 */	
1409
	private static boolean isMisappliedName(TaxonNameBase taxonName) {
1410
		boolean result = false;
1411
		Set<Taxon> taxa = taxonName.getTaxa();
1412
		if (taxa.size() == 1){
1413
			return isMisappliedName(taxa.iterator().next());
1414
		}else if (taxa.size() > 1){
1415
			logger.warn("TaxonNameBase has " + taxa.size() + " taxa attached. Can't define if it is a misapplied name.");
1416
		}
1417
		return result;
1418
	}
1419
		
1420
	
1421
	
1422

    
1423
	/**
1424
	 * Checks whether a given Taxon is a misapplied name.
1425
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1426
	 * @return Whether the given TaxonName is a misapplied name or not.
1427
	 */
1428
	private static boolean isMisappliedName(TaxonBase<?> taxon) {
1429
		boolean result = false;
1430
		
1431
		if (! taxon.isInstanceOf(Taxon.class)){
1432
			return false;
1433
		}
1434
		Set<TaxonRelationship> taxonRelations = CdmBase.deproxy(taxon, Taxon.class).getRelationsFromThisTaxon();
1435
		for (TaxonRelationship taxonRelationship : taxonRelations) {
1436
			TaxonRelationshipType taxonRelationshipType = taxonRelationship.getType();
1437
			if (taxonRelationshipType.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())) {
1438
				result = true;
1439
			}
1440
		}
1441
		return result;
1442
	}
1443
	
1444
	/**
1445
	 * Returns the <code>FullName</code> attribute.
1446
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1447
	 * @return The <code>FullName</code> attribute.
1448
	 * @see MethodMapper
1449
	 */
1450
	@SuppressWarnings("unused")
1451
	private static String getFullName(TaxonNameBase<?,?> taxonName) {
1452
		if (taxonName != null) {
1453
			return taxonName.getTitleCache();
1454
		} else {
1455
			return null;
1456
		}
1457
	}
1458
	
1459
	/**
1460
	 * Returns the <code>DisplayName</code> attribute.
1461
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1462
	 * @return The <code>DisplayName</code> attribute.
1463
	 * @see MethodMapper
1464
	 */
1465
	@SuppressWarnings("unused")
1466
	private static String getDisplayName(TaxonNameBase<?,?> taxonName) {
1467
		// TODO: extension?
1468
		if (taxonName != null) {
1469
			return taxonName.getFullTitleCache();
1470
		} else {
1471
			return null;
1472
		}
1473
	}
1474
	
1475
	/**
1476
	 * Returns the <code>NameStatusFk</code> attribute.
1477
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1478
	 * @return The <code>NameStatusFk</code> attribute.
1479
	 * @see MethodMapper
1480
	 */
1481
	@SuppressWarnings("unused")
1482
	private static Integer getNameStatusFk(TaxonNameBase<?,?> taxonName) {
1483
		Integer result = null;
1484

    
1485
		NomenclaturalStatus state = getNameStatus(taxonName);
1486
		if (state != null) {
1487
			result = PesiTransformer.nomStatus2nomStatusFk(state.getType());
1488
		}
1489
		return result;
1490
	}
1491
	
1492
	/**
1493
	 * Returns the <code>NameStatusCache</code> attribute.
1494
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1495
	 * @return The <code>NameStatusCache</code> attribute.
1496
	 * @see MethodMapper
1497
	 */
1498
	@SuppressWarnings("unused")
1499
	private static String getNameStatusCache(TaxonNameBase<?,?> taxonName) {
1500
		String result = null;
1501
		NomenclaturalStatus state = getNameStatus(taxonName);
1502
		if (state != null) {
1503
			result = PesiTransformer.nomStatus2NomStatusCache(state.getType());
1504
		}
1505
		return result;
1506
	}
1507
	
1508
	
1509
	private static NomenclaturalStatus getNameStatus(TaxonNameBase<?,?> taxonName) {
1510
		
1511
		try {
1512
			if (taxonName != null && (taxonName.isInstanceOf(NonViralName.class))) {
1513
				NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);
1514
				Set<NomenclaturalStatus> states = nonViralName.getStatus();
1515
				if (states.size() == 1) {
1516
					NomenclaturalStatus state = states.iterator().next();
1517
					return state;
1518
				} else if (states.size() > 1) {
1519
					logger.error("This TaxonName has more than one Nomenclatural Status: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1520
				}
1521
			}
1522
		
1523
		} catch (Exception e) {
1524
			e.printStackTrace();
1525
		}
1526
		return null;
1527
	}
1528
	/**
1529
	 * Returns the <code>TaxonStatusFk</code> attribute.
1530
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1531
	 * @param state The {@link PesiExportState PesiExportState}.
1532
	 * @return The <code>TaxonStatusFk</code> attribute.
1533
	 * @see MethodMapper
1534
	 */
1535
	@SuppressWarnings("unused")
1536
	private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {
1537
		Integer result = null;
1538
		
1539
		try {
1540
			if (isMisappliedName(taxon)) {
1541
				Synonym synonym = Synonym.NewInstance(null, null);
1542
				
1543
				// This works as long as only the instance is important to differentiate between TaxonStatus.
1544
				result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in Datawarehouse now.
1545
			} else {
1546
				result = PesiTransformer.taxonBase2statusFk(taxon);
1547
			}
1548
		
1549
		} catch (Exception e) {
1550
			e.printStackTrace();
1551
		}
1552
		return result;
1553
	}
1554
	
1555
	/**
1556
	 * Returns the <code>TaxonStatusCache</code> attribute.
1557
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1558
	 * @param state The {@link PesiExportState PesiExportState}.
1559
	 * @return The <code>TaxonStatusCache</code> attribute.
1560
	 * @see MethodMapper
1561
	 */
1562
	@SuppressWarnings("unused")
1563
	private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) {
1564
		String result = null;
1565
		
1566
		try {
1567
			if (isMisappliedName(taxon)) {
1568
				Synonym synonym = Synonym.NewInstance(null, null);
1569
				
1570
				// This works as long as only the instance is important to differentiate between TaxonStatus.
1571
				result = PesiTransformer.taxonBase2statusCache(synonym); // Auct References are treated as Synonyms in Datawarehouse now.
1572
			} else {
1573
				result = PesiTransformer.taxonBase2statusCache(taxon);
1574
			}
1575
		
1576
		} catch (Exception e) {
1577
			e.printStackTrace();
1578
		}
1579
		return result;
1580
	}
1581
	
1582
	/**
1583
	 * Returns the <code>TypeNameFk</code> attribute.
1584
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1585
	 * @param state The {@link PesiExportState PesiExportState}.
1586
	 * @return The <code>TypeNameFk</code> attribute.
1587
	 * @see MethodMapper
1588
	 */
1589
	private static Integer getTypeNameFk(TaxonNameBase<?,?> taxonNameBase, PesiExportState state) {
1590
		Integer result = null;
1591
		if (taxonNameBase != null) {
1592
			Set<NameTypeDesignation> nameTypeDesignations = taxonNameBase.getNameTypeDesignations();
1593
			if (nameTypeDesignations.size() == 1) {
1594
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1595
				if (nameTypeDesignation != null) {
1596
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1597
					if (typeName != null) {
1598
						result = state.getDbId(typeName);
1599
					}
1600
				}
1601
			} else if (nameTypeDesignations.size() > 1) {
1602
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonNameBase.getUuid() + " (" + taxonNameBase.getTitleCache() + ")");
1603
			}
1604
		}
1605
		return result;
1606
	}
1607
	
1608
	/**
1609
	 * Returns the <code>TypeFullnameCache</code> attribute.
1610
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1611
	 * @return The <code>TypeFullnameCache</code> attribute.
1612
	 * @see MethodMapper
1613
	 */
1614
	@SuppressWarnings("unused")
1615
	private static String getTypeFullnameCache(TaxonNameBase<?,?> taxonName) {
1616
		String result = null;
1617
		
1618
		try {
1619
		if (taxonName != null) {
1620
			Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
1621
			if (nameTypeDesignations.size() == 1) {
1622
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1623
				if (nameTypeDesignation != null) {
1624
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1625
					if (typeName != null) {
1626
						result = typeName.getTitleCache();
1627
					}
1628
				}
1629
			} else if (nameTypeDesignations.size() > 1) {
1630
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1631
			}
1632
		}
1633
		
1634
		} catch (Exception e) {
1635
			e.printStackTrace();
1636
		}
1637
		return result;
1638
	}
1639
	
1640
	/**
1641
	 * Returns the <code>QualityStatusFk</code> attribute.
1642
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1643
	 * @return The <code>QualityStatusFk</code> attribute.
1644
	 * @see MethodMapper
1645
	 */
1646
	@SuppressWarnings("unused")
1647
	private static Integer getQualityStatusFk(TaxonBase<?> taxonName) {
1648
		// TODO: Not represented in CDM right now. Depends on import.
1649
		Integer result = null;
1650
		return result;
1651
	}
1652
	
1653
	/**
1654
	 * Returns the <code>QualityStatusCache</code> attribute.
1655
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1656
	 * @return The <code>QualityStatusCache</code> attribute.
1657
	 * @see MethodMapper
1658
	 */
1659
	@SuppressWarnings("unused")
1660
	private static String getQualityStatusCache(TaxonBase<?> taxonName) {
1661
		// TODO: Not represented in CDM right now. Depends on import.
1662
		String result = null;
1663
		return result;
1664
	}
1665
	
1666
	/**
1667
	 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1668
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1669
	 * @return The <code>TypeDesignationStatusFk</code> attribute.
1670
	 * @see MethodMapper
1671
	 */
1672
	@SuppressWarnings("unused")
1673
	private static Integer getTypeDesignationStatusFk(TaxonNameBase<?,?> taxonName) {
1674
		Integer result = null;
1675
		
1676
		try {
1677
		if (taxonName != null) {
1678
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1679
			if (typeDesignations.size() == 1) {
1680
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1681
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1682
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);
1683
			} else if (typeDesignations.size() > 1) {
1684
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1685
			}
1686
		}
1687
		
1688
		} catch (Exception e) {
1689
			e.printStackTrace();
1690
		}
1691
		return result;
1692
	}
1693

    
1694
	/**
1695
	 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1696
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1697
	 * @return The <code>TypeDesignationStatusCache</code> attribute.
1698
	 * @see MethodMapper
1699
	 */
1700
	@SuppressWarnings("unused")
1701
	private static String getTypeDesignationStatusCache(TaxonNameBase<?,?> taxonName) {
1702
		String result = null;
1703
		
1704
		try {
1705
		if (taxonName != null) {
1706
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1707
			if (typeDesignations.size() == 1) {
1708
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1709
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1710
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);
1711
			} else if (typeDesignations.size() > 1) {
1712
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1713
			}
1714
		}
1715
		
1716
		} catch (Exception e) {
1717
			e.printStackTrace();
1718
		}
1719
		return result;
1720
	}
1721
	
1722
	/**
1723
	 * Returns the <code>FossilStatusFk</code> attribute.
1724
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1725
	 * @return The <code>FossilStatusFk</code> attribute.
1726
	 * @see MethodMapper
1727
	 */
1728
	@SuppressWarnings("unused")
1729
	private static Integer getFossilStatusFk(TaxonNameBase<?,?> taxonNameBase) {
1730
		Integer result = null;
1731
//		Taxon taxon;
1732
//		if (taxonBase.isInstanceOf(Taxon.class)) {
1733
//			taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1734
//			Set<TaxonDescription> specimenDescription = taxon.;
1735
//			result = PesiTransformer.fossil2FossilStatusId(fossil);
1736
//		}
1737
		return result;
1738
	}
1739
	
1740
	/**
1741
	 * Returns the <code>FossilStatusCache</code> attribute.
1742
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1743
	 * @return The <code>FossilStatusCache</code> attribute.
1744
	 * @see MethodMapper
1745
	 */
1746
	@SuppressWarnings("unused")
1747
	private static String getFossilStatusCache(TaxonNameBase<?,?> taxonName) {
1748
		// TODO
1749
		String result = null;
1750
		return result;
1751
	}
1752
	
1753
//	/**
1754
//	 * Returns the <code>IdInSource</code> attribute.
1755
//	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1756
//	 * @return The <code>IdInSource</code> attribute.
1757
//	 * @see MethodMapper
1758
//	 */
1759
//	@SuppressWarnings("unused")
1760
//	private static String getIdInSource(TaxonNameBase<?,?> taxonName) {
1761
//		String result = null;
1762
//		
1763
//		try {
1764
//			Set<IdentifiableSource> sources = getSources(taxonName);
1765
//			for (IdentifiableSource source : sources) {
1766
//				result = "TAX_ID: " + source.getIdInSource();
1767
//				String sourceIdNameSpace = source.getIdNamespace();
1768
//				if (sourceIdNameSpace != null) {
1769
//					if (sourceIdNameSpace.equals("originalGenusId")) {
1770
//						result = "Nominal Taxon from TAX_ID: " + source.getIdInSource();
1771
//					} else if (sourceIdNameSpace.equals("InferredEpithetOf")) {
1772
//						result = "Inferred epithet from TAX_ID: " + source.getIdInSource();
1773
//					} else if (sourceIdNameSpace.equals("InferredGenusOf")) {
1774
//						result = "Inferred genus from TAX_ID: " + source.getIdInSource();
1775
//					} else if (sourceIdNameSpace.equals("PotentialCombinationOf")) {
1776
//						result = "Potential combination from TAX_ID: " + source.getIdInSource();
1777
//					} else {
1778
//						result = "TAX_ID: " + source.getIdInSource();
1779
//					}
1780
//				}
1781
//			}
1782
//		} catch (Exception e) {
1783
//			e.printStackTrace();
1784
//		}
1785
//
1786
//		if (result == null) {
1787
//			logger.error("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1788
//		}
1789
//		return result;
1790
//	}
1791
	
1792
//	/**
1793
//	 * Returns the idInSource for a given TaxonName only.
1794
//	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1795
//	 * @return The idInSource.
1796
//	 */
1797
//	private static String getIdInSourceOnly(TaxonBase<?> taxonName) {
1798
//		String result = null;
1799
//		
1800
//		// Get the sources first
1801
//		Set<IdentifiableSource> sources = getSources(taxonName);
1802
//
1803
//		// Determine the idInSource
1804
//		if (sources.size() == 1) {
1805
//			IdentifiableSource source = sources.iterator().next();
1806
//			if (source != null) {
1807
//				result = source.getIdInSource();
1808
//			}
1809
//		} else if (sources.size() > 1) {
1810
//			int count = 1;
1811
//			result = "";
1812
//			for (IdentifiableSource source : sources) {
1813
//				result += source.getIdInSource();
1814
//				if (count < sources.size()) {
1815
//					result += "; ";
1816
//				}
1817
//				count++;
1818
//			}
1819
//
1820
//		}
1821
//		
1822
//		return result;
1823
//	}
1824
//	
1825
//	/**
1826
//	 * Returns the Sources for a given TaxonName only.
1827
//	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1828
//	 * @return The Sources.
1829
//	 */
1830
//	private static Set<IdentifiableSource> getSources(TaxonBase<?> taxon) {
1831
//		Set<IdentifiableSource> sources = null;
1832
//
1833
//		// Sources from TaxonName
1834
//		Set<IdentifiableSource> nameSources = taxon.getSources();
1835
//		sources = nameSources;
1836
//		if (nameSources.size() > 1) {
1837
//			logger.warn("This TaxonName has more than one Source: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1838
//		}
1839
//
1840
//		// Sources from TaxonBase
1841
//		if (sources == null || sources.isEmpty()) {
1842
//			Set<Taxon> taxa = taxonName.getTaxa();
1843
//			Set<Synonym> synonyms = taxonName.getSynonyms();
1844
//			if (taxa.size() == 1) {
1845
//				Taxon taxon = taxa.iterator().next();
1846
//
1847
//				if (taxon != null) {
1848
//					sources = taxon.getSources();
1849
//				}
1850
//			} else if (taxa.size() > 1) {
1851
//				logger.warn("This TaxonName has " + taxa.size() + " Taxa: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1852
//			}
1853
//			if (synonyms.size() == 1) {
1854
//				Synonym synonym = synonyms.iterator().next();
1855
//				
1856
//				if (synonym != null) {
1857
//					sources = synonym.getSources();
1858
//				}
1859
//			} else if (synonyms.size() > 1) {
1860
//				logger.warn("This TaxonName has " + synonyms.size() + " Synonyms: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1861
//			}
1862
//		}
1863
//		
1864
//		if (sources == null || sources.isEmpty()) {
1865
//			logger.error("This TaxonName has no Sources: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1866
//		}
1867
//		return sources;
1868
//	}
1869
	
1870
	/**
1871
	 * Returns the <code>GUID</code> attribute.
1872
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1873
	 * @return The <code>GUID</code> attribute.
1874
	 * @see MethodMapper
1875
	 */
1876
	private static String getGUID(TaxonBase<?> taxon) {
1877
		if (taxon.getLsid() != null ){
1878
			return taxon.getLsid().getLsid();
1879
		}else{
1880
			return taxon.getUuid().toString();
1881
		}
1882
	}
1883
	
1884
	/**
1885
	 * Returns the <code>DerivedFromGuid</code> attribute.
1886
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1887
	 * @return The <code>DerivedFromGuid</code> attribute.
1888
	 * @see MethodMapper
1889
	 */
1890
	@SuppressWarnings("unused")
1891
	private static String getDerivedFromGuid(TaxonBase<?> taxon) {
1892
		String result = null;
1893
		try {
1894
		// The same as GUID for now
1895
		result = getGUID(taxon);
1896
		} catch (Exception e) {
1897
			e.printStackTrace();
1898
		}
1899
		return result;
1900
	}
1901
	
1902
	/**
1903
	 * Returns the <code>CacheCitation</code> attribute.
1904
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1905
	 * @return The CacheCitation.
1906
	 * @see MethodMapper
1907
	 */
1908
	@SuppressWarnings("unused")
1909
	private static String getCacheCitation(TaxonBase<?> taxon) {
1910
		String result = "";
1911
		//TODO implement anew for taxa
1912
//		try {
1913
//			String originalDb = getOriginalDB(taxon);
1914
//			if (originalDb == null) {
1915
////				logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1916
//			} else if (originalDb.equals("ERMS")) {
1917
//				// 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...
1918
//				// 		 So the following code is some kind of harmless assumption.
1919
//				Set<Extension> extensions = taxon.getExtensions();
1920
//				for (Extension extension : extensions) {
1921
//					if (extension.getType().equals(cacheCitationExtensionType)) {
1922
//						result = extension.getValue();
1923
//					}
1924
//				}
1925
//			} else {
1926
//				String expertName = getExpertName(taxon);
1927
//				String webShowName = getWebShowName(taxon);
1928
//				
1929
//				// idInSource only
1930
//				String idInSource = getIdInSourceOnly(taxo);
1931
//				
1932
//				// build the cacheCitation
1933
//				if (expertName != null) {
1934
//					result += expertName + ". ";
1935
//				} else {
1936
//	//				logger.error("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1937
//				}
1938
//				if (webShowName != null) {
1939
//					result += webShowName + ". ";
1940
//				} else {
1941
//	//				logger.error("WebShowName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1942
//				}
1943
//				
1944
//				if (getOriginalDB(taxonName).equals("FaEu")) {
1945
//					result += "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
1946
//				} else if (getOriginalDB(taxonName).equals("EM")) {
1947
//					result += "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
1948
//				}
1949
//				
1950
//				if (idInSource != null) {
1951
//					result += idInSource;
1952
//				} else {
1953
//	//				logger.error("IdInSource could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1954
//				}
1955
//			}
1956
//		} catch (Exception e) {
1957
//			e.printStackTrace();
1958
//		}
1959
//		
1960
//		if ("".equals(result)) {
1961
//			return null;
1962
//		} else {
1963
//			return result;
1964
//		}
1965
		return result;
1966
	}
1967
	
1968
	/**
1969
	 * Returns the <code>OriginalDB</code> attribute.
1970
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1971
	 * @return The <code>OriginalDB</code> attribute.
1972
	 * @see MethodMapper
1973
	 */
1974
	private static String getOriginalDB(IdentifiableEntity identEntity) {
1975
		String result = "";
1976
		try {
1977

    
1978
		// Sources from TaxonName
1979
//		Set<IdentifiableSource> sources = taxonName.getSources();
1980
		Set<IdentifiableSource>  sources  = identEntity.getSources();
1981
		
1982
//		IdentifiableEntity<?> taxonBase = null;
1983
//		if (sources != null && sources.isEmpty()) {
1984
//			// Sources from Taxa or Synonyms
1985
//			Set<Taxon> taxa = taxonName.getTaxa();
1986
//			if (taxa.size() == 1) {
1987
//				taxonBase = taxa.iterator().next();
1988
//				sources  = taxonBase.getSources();
1989
//			} else if (taxa.size() > 1) {
1990
//				logger.warn("This TaxonName has " + taxa.size() + " Taxa: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1991
//			}
1992
//			Set<Synonym> synonyms = taxonName.getSynonyms();
1993
//			if (synonyms.size() == 1) {
1994
//				taxonBase = synonyms.iterator().next();
1995
//				sources = taxonBase.getSources();
1996
//			} else if (synonyms.size() > 1) {
1997
//				logger.warn("This TaxonName has " + synonyms.size() + " Synonyms: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
1998
//			}
1999
//		}
2000

    
2001
		if (sources != null && ! sources.isEmpty()) {
2002
			if (sources.size() == 1) {
2003
				IdentifiableSource source = sources.iterator().next();
2004
				if (source != null) {
2005
					Reference<?> citation = source.getCitation();
2006
					if (citation != null) {
2007
						result = PesiTransformer.databaseString2Abbreviation(citation.getTitleCache());
2008
					}
2009
				}
2010
			} else if (sources.size() > 1) {
2011
				int count = 1;
2012
				for (IdentifiableSource source : sources) {
2013
					Reference<?> citation = source.getCitation();
2014
					if (citation != null) {
2015
						if (count > 1) {
2016
							result += "; ";
2017
						}
2018
						result += PesiTransformer.databaseString2Abbreviation(citation.getTitleCache());
2019
						count++;
2020
					}
2021
				}
2022
			} else {
2023
				result = null;
2024
			}
2025
		}
2026

    
2027
		} catch (Exception e) {
2028
			e.printStackTrace();
2029
		}
2030
		if ("".equals(result)) {
2031
			return null;
2032
		} else {
2033
			return result;
2034
		}
2035
	}
2036
	
2037
	/**
2038
	 * Returns the <code>LastAction</code> attribute.
2039
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2040
	 * @return The <code>LastAction</code> attribute.
2041
	 * @see MethodMapper
2042
	 */
2043
	@SuppressWarnings("unused")
2044
	private static String getLastAction(IdentifiableEntity<?> identEntity) {
2045
		String result = null;
2046
		try {
2047
		Set<Extension> extensions = identEntity.getExtensions();
2048
		for (Extension extension : extensions) {
2049
			if (extension.getType().equals(lastActionExtensionType)) {
2050
				result = extension.getValue();
2051
			}
2052
		}
2053
		} catch (Exception e) {
2054
			e.printStackTrace();
2055
		}
2056
		return result;
2057
	}
2058
	
2059
	/**
2060
	 * Returns the <code>LastActionDate</code> attribute.
2061
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2062
	 * @return The <code>LastActionDate</code> attribute.
2063
	 * @see MethodMapper
2064
	 */
2065
	@SuppressWarnings({ "unused" })
2066
	private static DateTime getLastActionDate(IdentifiableEntity identEntity) {
2067
		DateTime result = null;
2068
		try {
2069
			Set<Extension> extensions = identEntity.getExtensions();
2070
			for (Extension extension : extensions) {
2071
				if (extension.getType().equals(lastActionDateExtensionType)) {
2072
					String dateTime = extension.getValue();
2073
					if (dateTime != null) {
2074
						DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S");
2075
						result = formatter.parseDateTime(dateTime);
2076
					}
2077
				}
2078
			}
2079
		} catch (Exception e) {
2080
			e.printStackTrace();
2081
		}
2082
		return result;
2083
	}
2084
	
2085
	/**
2086
	 * Returns the <code>ExpertName</code> attribute.
2087
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2088
	 * @return The <code>ExpertName</code> attribute.
2089
	 * @see MethodMapper
2090
	 */
2091
	@SuppressWarnings("unused")
2092
	private static String getExpertName(TaxonBase<?> taxonName) {
2093
		String result = null;
2094
		try {
2095
		Set<Extension> extensions = taxonName.getExtensions();
2096
		for (Extension extension : extensions) {
2097
			if (extension.getType().equals(expertNameExtensionType)) {
2098
				result = extension.getValue();
2099
			}
2100
		}
2101
		} catch (Exception e) {
2102
			e.printStackTrace();
2103
		}
2104
		return result;
2105
	}
2106
	
2107
	/**
2108
	 * Returns the <code>ExpertFk</code> attribute.
2109
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2110
	 * @param state The {@link PesiExportState PesiExportState}.
2111
	 * @return The <code>ExpertFk</code> attribute.
2112
	 * @see MethodMapper
2113
	 */
2114
	private static Integer getExpertFk(Reference<?> reference, PesiExportState state) {
2115
		Integer result = state.getDbId(reference);
2116
		return result;
2117
	}
2118
	
2119
	/**
2120
	 * Returns the <code>SpeciesExpertName</code> attribute.
2121
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2122
	 * @return The <code>SpeciesExpertName</code> attribute.
2123
	 * @see MethodMapper
2124
	 */
2125
	@SuppressWarnings("unused")
2126
	private static String getSpeciesExpertName(TaxonBase<?> taxonName) {
2127
		String result = null;
2128
		try {
2129
		Set<Extension> extensions = taxonName.getExtensions();
2130
		for (Extension extension : extensions) {
2131
			if (extension.getType().equals(speciesExpertNameExtensionType)) {
2132
				result = extension.getValue();
2133
			}
2134
		}
2135
		} catch (Exception e) {
2136
			e.printStackTrace();
2137
		}
2138
		return result;
2139
	}
2140
	
2141
	/**
2142
	 * Returns the <code>SpeciesExpertFk</code> attribute.
2143
	 * @param reference The {@link Reference Reference}.
2144
	 * @param state The {@link PesiExportState PesiExportState}.
2145
	 * @return The <code>SpeciesExpertFk</code> attribute.
2146
	 * @see MethodMapper
2147
	 */
2148
	private static Integer getSpeciesExpertFk(Reference<?> reference, PesiExportState state) {
2149
		Integer result = state.getDbId(reference);
2150
		return result;
2151
	}
2152

    
2153
//	/**
2154
//	 * Returns the <code>SourceFk</code> attribute.
2155
//	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2156
//	 * @param state The {@link PesiExportState PesiExportState}.
2157
//	 * @return The <code>SourceFk</code> attribute.
2158
//	 */
2159
//	@SuppressWarnings("unused")
2160
//	private static Integer getSourceFk(TaxonNameBase<?,?> taxonName, PesiExportState state) {
2161
//		Integer result = null;
2162
//		
2163
//		try {
2164
//			TaxonBase<?> taxonBase = getSourceTaxonBase(taxonName);
2165
//	
2166
//			if (taxonBase != null) {
2167
//				result = state.getDbId(taxonBase.getSec());
2168
//			}
2169
//		} catch (Exception e) {
2170
//			e.printStackTrace();
2171
//		}
2172
//		return result;
2173
//	}
2174

    
2175

    
2176
//	/**
2177
//	 * Determines the TaxonBase of a TaxonName.
2178
//	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2179
//	 * @return The TaxonBase.
2180
//	 */
2181
//	private static TaxonBase<?> getSourceTaxonBase(TaxonNameBase<?,?> taxonName) {
2182
//		TaxonBase<?> taxonBase = null;
2183
//		Set<Taxon> taxa = taxonName.getTaxa();
2184
//		if (taxa.size() == 1) {
2185
//			taxonBase =taxa.iterator().next();
2186
//		} else if (taxa.size() > 1) {
2187
//			logger.warn("This TaxonName has " + taxa.size() + " Taxa: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2188
//		}
2189
//		
2190
//		Set<Synonym> synonyms  = taxonName.getSynonyms();
2191
//		if (synonyms.size() == 1) {
2192
//			taxonBase = synonyms.iterator().next();
2193
//		} else if (synonyms.size() > 1) {
2194
//			logger.warn("This TaxonName has " + synonyms.size() + " Synonyms: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2195
//		}
2196
//		return taxonBase;
2197
//	}
2198

    
2199
}
(14-14/15)