Project

General

Profile

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

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

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

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

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

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

    
131

    
132
	/**
133
	 * @return the treeIndexAnnotationType
134
	 */
135
	protected AnnotationType getTreeIndexAnnotationType() {
136
		return treeIndexAnnotationType;
137
	}
138

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

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

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

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

    
166
	/* (non-Javadoc)
167
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
168
	 */
169
	@Override
170
	protected boolean doCheck(PesiExportState state) {
171
		boolean result = true;
172
		return result;
173
	}
174

    
175

    
176
	/* (non-Javadoc)
177
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
178
	 */
179
	@Override
180
	protected void doInvoke(PesiExportState state) {
181
		try {
182
			logger.info("*** Started Making " + pluralString + " ...");
183

    
184
			initPreparedStatements(state);
185

    
186
			// Stores whether this invoke was successful or not.
187
			boolean success = true;
188

    
189
			// PESI: Clear the database table Taxon.
190
//			doDelete(state);
191

    
192
			// Get specific mappings: (CDM) Taxon -> (PESI) Taxon
193
			PesiExportMapping mapping = getMapping();
194
			PesiExportMapping synonymRelMapping = getSynRelMapping();
195
			PesiExportMapping additionalSourceMapping = getAdditionalSourceMapping(state);
196

    
197
			// Initialize the db mapper
198
			mapping.initialize(state);
199
			synonymRelMapping.initialize(state);
200
			additionalSourceMapping.initialize(state);
201

    
202
			// Find extensionTypes
203
			lastActionExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionUuid);
204
			lastActionDateExtensionType = (ExtensionType)getTermService().find(PesiTransformer.lastActionDateUuid);
205
			expertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
206
			speciesExpertNameExtensionType = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
207
			cacheCitationExtensionType = (ExtensionType)getTermService().find(PesiTransformer.cacheCitationUuid);
208

    
209
			//Export Taxa..
210
			success &= doPhase01(state, mapping, additionalSourceMapping);
211

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

    
215

    
216
			// 2nd Round: Add ParentTaxonFk to each taxon
217
			success &= doPhase02(state);
218

    
219
			//PHASE 3: Add Rank data, KingdomFk, TypeNameFk ...
220
			success &= doPhase03(state);
221

    
222
			// 4nd Round: Add TreeIndex to each taxon
223
			success &= doPhase04(state);
224

    
225

    
226
			//"PHASE 4: Creating Inferred Synonyms...
227
			success &= doPhase05(state, mapping, synonymRelMapping);
228

    
229
			logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
230

    
231
			if (!success){
232
				state.setUnsuccessfull();
233
			}
234
			return;
235
		} catch (Exception e) {
236
			e.printStackTrace();
237
			logger.error(e.getMessage());
238
			state.setUnsuccessfull();
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, PesiExportMapping additionalSourceMapping) 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.info("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.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
305

    
306
			for (TaxonBase<?> taxon : list) {
307
				doCount(count++, modCount, pluralString);
308
				TaxonNameBase<?,?> taxonName = taxon.getName();
309

    
310
				NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
311
				System.err.println(nvn.getTitleCache());
312
				if (! nvn.isProtectedTitleCache()){
313
					nvn.setTitleCache(null, false);
314
				}
315
				if (! nvn.isProtectedNameCache()){
316
					nvn.setNameCache(null, false);
317
				}
318
				if (! nvn.isProtectedFullTitleCache()){
319
					nvn.setFullTitleCache(null, false);
320
				}
321
				if (! nvn.isProtectedAuthorshipCache()){
322
					nvn.setAuthorshipCache(null, false);
323
				}
324
				try{
325
				if (nvn.getRank().equals(Rank.KINGDOM())){
326
				    String treeIndex = ((Taxon)taxon).getTaxonNodes().iterator().next().treeIndex();
327
				    Integer kingdomId = PesiTransformer.pesiKingdomMap.get(nvn.getGenusOrUninomial());
328
				    state.getTreeIndexKingdomMap().put(treeIndex, kingdomId);
329
				}}catch(NullPointerException e){
330
				    logger.error(nvn.getTitleCache() + "has no Rank!");
331
				    System.err.println(nvn.getTitleCache() + "has no Rank!");
332
				}
333
				//core mapping
334
				success &= mapping.invoke(taxon);
335
				//additional source
336
				if (nvn.getNomenclaturalReference() != null || StringUtils.isNotBlank(nvn.getNomenclaturalMicroReference() )){
337
					additionalSourceMapping.invoke(taxon);
338
				}
339

    
340
				validatePhaseOne(taxon, nvn);
341
				taxon = null;
342
				nvn = null;
343
				taxonName = null;
344

    
345

    
346

    
347
			}
348

    
349

    
350
			// Commit transaction
351
			commitTransaction(txStatus);
352
			logger.debug("Committed transaction.");
353
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
354
			pastCount = count;
355
			/*logger.warn("Taking snapshot at the end of the loop of phase 1 of taxonExport");
356
			//ProfilerController.memorySnapshot();
357
			*/
358
			// Start transaction
359
			txStatus = startTransaction(true);
360
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
361

    
362
		}
363
		if (list == null ) {
364
			logger.info("No " + pluralString + " left to fetch.");
365
		}
366

    
367

    
368

    
369
		// Commit transaction
370
		commitTransaction(txStatus);
371
		txStatus = null;
372
		logger.debug("Committed transaction.");
373
		list = null;
374
		if (logger.isDebugEnabled()){
375
			logger.debug("Taking snapshot at the end of phase 1 of taxonExport");
376
			ProfilerController.memorySnapshot();
377
		}
378
		return success;
379
	}
380

    
381

    
382
	private void validatePhaseOne(TaxonBase<?> taxon, NonViralName taxonName) {
383
		// Check whether some rules are violated
384
		nomenclaturalCode = taxonName.getNomenclaturalCode();
385
		String genusOrUninomial = taxonName.getGenusOrUninomial();
386
		String specificEpithet = taxonName.getSpecificEpithet();
387
		String infraSpecificEpithet = taxonName.getInfraSpecificEpithet();
388
		String infraGenericEpithet = taxonName.getInfraGenericEpithet();
389
		Integer rank = getRankFk(taxonName, nomenclaturalCode);
390

    
391
		if (rank == null) {
392
			logger.error("Rank was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
393
		} else {
394

    
395
			// Check whether infraGenericEpithet is set correctly
396
			// 1. Childs of an accepted taxon of rank subgenus that are accepted taxa of rank species have to have an infraGenericEpithet
397
			// 2. Grandchilds of an accepted taxon of rank subgenus that are accepted taxa of rank subspecies have to have an infraGenericEpithet
398

    
399
			int ancestorLevel = 0;
400
			if (taxonName.getRank().equals(Rank.SUBSPECIES())) {
401
				// The accepted taxon two rank levels above should be of rank subgenus
402
				ancestorLevel  = 2;
403
			}
404
			if (taxonName.getRank().equals(Rank.SPECIES())) {
405
				// The accepted taxon one rank level above should be of rank subgenus
406
				ancestorLevel = 1;
407
			}
408
			if (ancestorLevel > 0) {
409
				if (validateAncestorOfSpecificRank(taxon, ancestorLevel, Rank.SUBGENUS())) {
410
					// The child (species or subspecies) of this parent (subgenus) has to have an infraGenericEpithet
411
					if (infraGenericEpithet == null) {
412
						logger.warn("InfraGenericEpithet for (sub)species of infrageneric taxon does not exist even though it should (also valid for Botanical Names?) for: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
413
						// maybe the taxon could be named here
414
					}
415
				}
416
			}
417

    
418
			if (infraGenericEpithet == null && rank.intValue() == 190) {
419
				logger.warn("InfraGenericEpithet was not determined although it should exist for rank 190: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
420
			}
421
			if (specificEpithet != null && rank.intValue() < 216) {
422
				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() + ")");
423
			}
424
			if (infraSpecificEpithet != null && rank.intValue() < 225) {
425
				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() + ")";
426
				if (StringUtils.isNotBlank(infraSpecificEpithet)){
427
					logger.warn(message);
428
				}else{
429
					logger.warn(message);
430
				}
431
			}
432
		}
433
		if (infraSpecificEpithet != null && specificEpithet == null) {
434
			logger.warn("An infraSpecificEpithet was determined, but a specificEpithet was not determined: "  + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
435
		}
436
		if (genusOrUninomial == null) {
437
			logger.warn("GenusOrUninomial was not determined: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
438
		}
439
	}
440

    
441

    
442

    
443
	/**
444
	 * 2nd Round: Add ParentTaxonFk to each taxon and add Biota if not exists
445
	 * @param state
446
	 * @return
447
	 */
448
	private boolean doPhase02(PesiExportState state) {
449
		int count = 0;
450
		int pastCount = 0;
451
		boolean success = true;
452
		if (! state.getConfig().isDoParentAndBiota()){
453
			logger.info ("Ignore PHASE 2: Make ParentFk and Biota...");
454
			return success;
455
		}
456

    
457
		List<Taxon> list;
458

    
459
		// Get the limit for objects to save within a single transaction.
460
		int limit = state.getConfig().getLimitSave();
461

    
462
		insertBiota(state);
463

    
464
		logger.info("PHASE 2: Make ParentFk and Biota ... limit is " + limit);
465
		// Start transaction
466
		TransactionStatus txStatus = startTransaction(true);
467
		int partitionCount = 0;
468

    
469
//		ProfilerController.memorySnapshot();
470
		while ((list = getNextTaxonPartition(Taxon.class, limit, partitionCount++, null)) != null   ) {
471

    
472
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
473
			for (Taxon taxon : list) {
474
				for (TaxonNode node : taxon.getTaxonNodes()){
475
					doCount(count++, modCount, pluralString);
476
					TaxonNode parentNode = node.getParent();
477
					if (parentNode != null && parentNode.getTaxon() != null){  //new root node handling requires has root taxon with taxon == null
478
						int childId = state.getDbId( taxon);
479
						int parentId = state.getDbId(parentNode.getTaxon());
480
						success &= invokeParentTaxonFk(parentId, childId);
481
					}
482
				}
483

    
484
			}
485

    
486
			// Commit transaction
487
			commitTransaction(txStatus);
488
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
489
			pastCount = count;
490
			// Start transaction
491
			txStatus = startTransaction(true);
492
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
493

    
494
		}
495
		if (list == null ) {
496
			logger.info("No " + pluralString + " left to fetch.");
497
		}
498
		list = null;
499
		// Commit transaction
500
		commitTransaction(txStatus);
501

    
502
		return success;
503

    
504
	}
505

    
506
	/**
507
	 * Inserts the Biota Taxon if not yet exists.
508
	 * @param state
509
	 * @throws SQLException
510
	 */
511
	private void insertBiota(PesiExportState state) {
512
		try {
513
			ResultSet rs = state.getConfig().getDestination().getResultSet("SELECT * FROM Taxon WHERE GenusOrUninomial = 'Biota' ");
514
			if (rs.next() == false){
515
				int biotaId = state.getConfig().getNameIdStart() -1 ;
516
				String sqlInsertBiota = "INSERT INTO Taxon (TaxonId, KingdomFk, RankFk, RankCache, GenusOrUninomial, WebSearchName, WebShowName, FullName, DisplayName, TaxonStatusFk, TaxonStatusCache) " +
517
									       " VALUES (" + biotaId + ",    0,    0,   'Superdomain',   'Biota',          'Biota',  '<i>Biota</i>',   'Biota', '<i>Biota</i>',  1 ,      'accepted')";
518
				state.getConfig().getDestination().update(sqlInsertBiota);
519
			}
520
			rs = null;
521
		} catch (SQLException e) {
522
			logger.warn ("Biota could not be requested or inserted");
523
		}
524

    
525
	}
526

    
527
	// 4th round: Add TreeIndex to each taxon
528
	private boolean doPhase04(PesiExportState state) {
529
		boolean success = true;
530

    
531
		logger.info("PHASE 4: Make TreeIndex ... ");
532

    
533
		//TODO test if possible to move to phase 02
534
		String sql = " UPDATE Taxon SET ParentTaxonFk = (Select TaxonId from Taxon where RankFk = 0) " +
535
				" WHERE (RankFk = 10) and TaxonStatusFk = 1 ";
536
		state.getConfig().getDestination().update(sql);
537

    
538
		state.getConfig().getDestination().update("EXEC dbo.recalculateallstoredpaths");
539

    
540
		return success;
541

    
542
	}
543

    
544

    
545
	// 2nd Round: Add ParentTaxonFk, TreeIndex to each Taxon
546
	private boolean doPhase02_OLD(PesiExportState state) {
547
		boolean success = true;
548
		if (! state.getConfig().isDoTreeIndex()){
549
			logger.info ("Ignore PHASE 2: ParentTaxonFk and TreeIndex");
550
			return success;
551
		}
552

    
553
		List<Classification> classificationList = null;
554
		logger.info("PHASE 2: Add ParenTaxonFk and TreeIndex...");
555

    
556
		// Specify starting ranks for tree traversing
557
		rankList.add(Rank.KINGDOM());
558
		rankList.add(Rank.GENUS());
559

    
560
		// Specify where to stop traversing (value) when starting at a specific Rank (key)
561
		rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
562
		rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
563

    
564
		StringBuffer treeIndex = new StringBuffer();
565

    
566
		// Retrieve list of classifications
567
		TransactionStatus txStatus = startTransaction(true);
568
		logger.info("Started transaction for parentFk and treeIndex. Fetching all classifications...");
569
		classificationList = getClassificationService().listClassifications(null, 0, null, null);
570
		commitTransaction(txStatus);
571
		logger.debug("Committed transaction.");
572

    
573
		logger.info("Fetched " + classificationList.size() + " classification(s).");
574

    
575
		setTreeIndexAnnotationType(getAnnotationType(uuidTreeIndex, "TreeIndex", "TreeIndex", "TI"));
576
		List<TaxonNode> rankSpecificRootNodes;
577
		for (Classification classification : classificationList) {
578
			for (Rank rank : rankList) {
579

    
580
				txStatus = startTransaction(true);
581
				logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
582

    
583
				rankSpecificRootNodes = getClassificationService().listRankSpecificRootNodes(classification, rank, null, null, null);
584
				logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
585

    
586
				commitTransaction(txStatus);
587
				logger.debug("Committed transaction.");
588

    
589
				for (TaxonNode rootNode : rankSpecificRootNodes) {
590
					txStatus = startTransaction(false);
591
					Rank endRank = rank2endRankMap.get(rank);
592
					if (endRank != null) {
593
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till Rank " + endRank.getLabel() + " ...");
594
					} else {
595
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till leaves are reached ...");
596
					}
597

    
598
					TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
599

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

    
640
					newNode = null;
641

    
642
					try {
643
						commitTransaction(txStatus);
644
						logger.debug("Committed transaction.");
645
					} catch (Exception e) {
646
						logger.error(e.getMessage());
647
						e.printStackTrace();
648
					}
649

    
650
				}
651
				rankSpecificRootNodes = null;
652
			}
653

    
654
		}
655

    
656
		logger.warn("Taking snapshot at the end of phase 2 of taxonExport");
657
		//ProfilerController.memorySnapshot();
658
		return success;
659
	}
660

    
661
	//PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...
662
	private boolean doPhase03(PesiExportState state) {
663
		int count = 0;
664
		int pastCount = 0;
665
		boolean success = true;
666
		if (! state.getConfig().isDoTreeIndex()){
667
			logger.info ("Ignore PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
668
			return success;
669
		}
670
		// Get the limit for objects to save within a single transaction.
671
		int limit = state.getConfig().getLimitSave();
672

    
673
		List<TaxonBase> list;
674
		logger.info("PHASE 3: Add Rank data, KingdomFk, TypeNameFk, expertFk and speciesExpertFk...");
675
		// Be sure to add rank information, KingdomFk, TypeNameFk, expertFk and speciesExpertFk to every taxonName
676

    
677
		// Start transaction
678
		TransactionStatus txStatus = startTransaction(true);
679
		logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
680
		int partitionCount = 0;
681
		while ((list = getNextTaxonPartition(TaxonBase.class, limit, partitionCount++, null)) != null) {
682

    
683
			logger.debug("Fetched " + list.size() + " " + pluralString + ". Exporting...");
684
			for (TaxonBase<?> taxon : list) {
685
				TaxonNameBase<?,?> taxonName = taxon.getName();
686
				// Determine expertFk
687
//				Integer expertFk = makeExpertFk(state, taxonName);
688
//
689
//				// Determine speciesExpertFk
690
//				Integer speciesExpertFk = makeSpeciesExpertFk(state, taxonName);
691

    
692
				doCount(count++, modCount, pluralString);
693
				Integer typeNameFk = getTypeNameFk(taxonName, state);
694
				kingdomFk = findKingdomIdFromTreeIndex(taxon, state);
695
				 //       PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
696

    
697
				//TODO why are expertFks needed? (Andreas M.)
698
//				if (expertFk != null || speciesExpertFk != null) {
699
					invokeRankDataAndTypeNameFkAndKingdomFk(taxonName, nomenclaturalCode, state.getDbId(taxon),
700
							typeNameFk, kingdomFk, state);
701
//				}
702

    
703
					taxon = null;
704
					taxonName = null;
705
			}
706

    
707
			// Commit transaction
708
			commitTransaction(txStatus);
709
			logger.debug("Committed transaction.");
710
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
711
			pastCount = count;
712

    
713
			// Start transaction
714
			txStatus = startTransaction(true);
715
			logger.info("Started new transaction for rank, kingdom, typeName, expertFk and speciesExpertFK. Fetching some " + pluralString + " (max: " + limit + ") ...");
716
		}
717
		if (list == null) {
718
			logger.info("No " + pluralString + " left to fetch.");
719
		}
720

    
721
		list = null;
722

    
723
		// Commit transaction
724
		commitTransaction(txStatus);
725

    
726
		logger.debug("Committed transaction.");
727
		logger.debug("Try to take snapshot at the end of phase 3 of taxonExport, number of partitions: " + partitionCount);
728
		//ProfilerController.memorySnapshot();
729
		return success;
730
	}
731

    
732
	/**
733
     * @param taxon
734
     * @return
735
     */
736
    private Integer findKingdomIdFromTreeIndex(TaxonBase<?> taxon,PesiExportState state) {
737
        if (taxon instanceof Taxon){
738
            Set<TaxonNode> nodes = ((Taxon)taxon).getTaxonNodes();
739
            if (!nodes.isEmpty()){
740
                String treeIndex = nodes.iterator().next().treeIndex();
741

    
742
                Pattern pattern = Pattern.compile("#t[0-9]+#[0-9]+#[0-9]+#");
743
                Matcher matcher = pattern.matcher(treeIndex);
744
                Integer kingdomID = null;
745
                if(matcher.find()) {
746
                    String treeIndexKingdom = matcher.group(0);
747
                    kingdomID = state.getTreeIndexKingdomMap().get(treeIndexKingdom);
748
                }
749
                return kingdomID;
750
            } else {
751
                logger.debug("The taxon has no nodes: " + taxon.getTitleCache() + " the kingdom is taken from the nomenclatural code: " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
752
                return PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
753
        }} else{
754
           return PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
755
        }
756
    }
757

    
758
    //	"PHASE 5: Creating Inferred Synonyms..."
759
	private boolean doPhase05(PesiExportState state, PesiExportMapping mapping, PesiExportMapping synRelMapping) throws SQLException {
760
		int count;
761
		int pastCount;
762
		boolean success = true;
763
		// Get the limit for objects to save within a single transaction.
764
		if (! state.getConfig().isDoInferredSynonyms()){
765
			logger.info ("Ignore PHASE 5: Creating Inferred Synonyms...");
766
			return success;
767
		}
768

    
769
		int limit = state.getConfig().getLimitSave();
770
		// Create inferred synonyms for accepted taxa
771
		logger.info("PHASE 4: Creating Inferred Synonyms...");
772

    
773
		// Determine the count of elements in datawarehouse database table Taxon
774
		currentTaxonId = determineTaxonCount(state);
775
		currentTaxonId++;
776

    
777
		count = 0;
778
		pastCount = 0;
779
		int pageSize = limit/10;
780
		int pageNumber = 1;
781
		String inferredSynonymPluralString = "Inferred Synonyms";
782

    
783
		// Start transaction
784
		TransactionStatus txStatus = startTransaction(true);
785
		logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
786
		List<TaxonBase> taxonList = null;
787

    
788

    
789

    
790
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", "*", Rank.SPECIES(), pageSize, pageNumber)).size() > 0) {
791
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
792

    
793
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
794
			inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
795
					synRelMapping, taxonList));
796

    
797
			doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
798
			// Commit transaction
799
			commitTransaction(txStatus);
800
			logger.debug("Committed transaction.");
801
			logger.info("Exported " + (taxonList.size()) + " " + inferredSynonymPluralString + ". Total: " + count);
802
			//pastCount = count;
803

    
804
			// Save Rank Data and KingdomFk for inferred synonyms
805
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
806
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);
807
			}
808

    
809
			// Start transaction
810
			txStatus = startTransaction(true);
811
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
812

    
813
			// Increment pageNumber
814
			pageNumber++;
815
		}
816
		taxonList = null;
817
		while ((taxonList  = getTaxonService().listTaxaByName(Taxon.class, "*", "*", "*", "*", "*", Rank.SUBSPECIES(), pageSize, pageNumber)).size() > 0) {
818
			HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
819

    
820
			logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
821
			inferredSynonymsDataToBeSaved.putAll(createInferredSynonymsForTaxonList(state, mapping,
822
					synRelMapping, taxonList));
823
			;
824
			doCount(count += taxonList.size(), modCount, inferredSynonymPluralString);
825
			// Commit transaction
826
			commitTransaction(txStatus);
827
			logger.debug("Committed transaction.");
828
			logger.info("Exported " + taxonList.size()+ " " + inferredSynonymPluralString + ". Total: " + count);
829
			//pastCount = count;
830

    
831
			// Save Rank Data and KingdomFk for inferred synonyms
832
			for (Integer taxonFk : inferredSynonymsDataToBeSaved.keySet()) {
833
				invokeRankDataAndKingdomFk(inferredSynonymsDataToBeSaved.get(taxonFk), nomenclaturalCode, taxonFk, kingdomFk, state);
834
			}
835

    
836
			// Start transaction
837
			txStatus = startTransaction(true);
838
			logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
839

    
840
			// Increment pageNumber
841
			pageNumber++;
842
			inferredSynonymsDataToBeSaved = null;
843
		}
844
		if (taxonList.size() == 0) {
845
			logger.info("No " + parentPluralString + " left to fetch.");
846
		}
847

    
848
		taxonList = null;
849
//		logger.warn("Taking snapshot at the end of phase 4 of taxonExport");
850
//		ProfilerController.memorySnapshot();
851

    
852
		// Commit transaction
853
		commitTransaction(txStatus);
854
		System.gc();
855
		logger.debug("Taking snapshot at the end of phase 4 after gc() of taxonExport");
856
		//ProfilerController.memorySnapshot();
857
		logger.debug("Committed transaction.");
858
		return success;
859
	}
860

    
861
	/**
862
	 * @param state
863
	 * @param mapping
864
	 * @param synRelMapping
865
	 * @param currentTaxonId
866
	 * @param taxonList
867
	 * @param inferredSynonymsDataToBeSaved
868
	 * @return
869
	 */
870
	private HashMap<Integer, TaxonNameBase<?, ?>> createInferredSynonymsForTaxonList(PesiExportState state,
871
			PesiExportMapping mapping, PesiExportMapping synRelMapping,	 List<TaxonBase> taxonList) {
872

    
873
		Taxon acceptedTaxon;
874
		Classification classification = null;
875
		List<Synonym> inferredSynonyms = null;
876
		boolean localSuccess = true;
877

    
878
		HashMap<Integer, TaxonNameBase<?,?>> inferredSynonymsDataToBeSaved = new HashMap<Integer, TaxonNameBase<?,?>>();
879

    
880
		for (TaxonBase<?> taxonBase : taxonList) {
881

    
882
			if (taxonBase.isInstanceOf(Taxon.class)) { // this should always be the case since we should have fetched accepted taxon only, but you never know...
883
				acceptedTaxon = CdmBase.deproxy(taxonBase, Taxon.class);
884
				TaxonNameBase<?,?> taxonName = acceptedTaxon.getName();
885

    
886
				if (taxonName.isInstanceOf(ZoologicalName.class)) {
887
					nomenclaturalCode  = taxonName.getNomenclaturalCode();
888
					kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode);
889

    
890
					Set<TaxonNode> taxonNodes = acceptedTaxon.getTaxonNodes();
891
					TaxonNode singleNode = null;
892

    
893
					if (taxonNodes.size() > 0) {
894
						// Determine the classification of the current TaxonNode
895

    
896
						singleNode = taxonNodes.iterator().next();
897
						if (singleNode != null) {
898
							classification = singleNode.getClassification();
899
						} else {
900
							logger.error("A TaxonNode belonging to this accepted Taxon is NULL: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() +")");
901
						}
902
					} else {
903
						// Classification could not be determined directly from this TaxonNode
904
						// The stored classification from another TaxonNode is used. It's a simple, but not a failsafe fallback solution.
905
						if (taxonNodes.size() == 0) {
906
							//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");
907

    
908
						}
909
					}
910

    
911
					if (classification != null) {
912
						try{
913
							TaxonNameBase name = acceptedTaxon.getName();
914
							//if (name.isSpecies() || name.isInfraSpecific()){
915
								inferredSynonyms  = getTaxonService().createAllInferredSynonyms(acceptedTaxon, classification, true);
916
							//}
917
//								inferredSynonyms = getTaxonService().createInferredSynonyms(classification, acceptedTaxon, SynonymType.INFERRED_GENUS_OF());
918
							if (inferredSynonyms != null) {
919
								for (Synonym synonym : inferredSynonyms) {
920
//									TaxonNameBase<?,?> synonymName = synonym.getName();
921
									MarkerType markerType =getUuidMarkerType(PesiTransformer.uuidMarkerGuidIsMissing, state);
922
									synonym.addMarker(Marker.NewInstance(markerType, true));
923
									// Both Synonym and its TaxonName have no valid Id yet
924
									synonym.setId(currentTaxonId++);
925

    
926

    
927
									localSuccess &= mapping.invoke(synonym);
928
									//get SynonymRelationship and export
929
									if (synonym.getAcceptedTaxon() == null ){
930
										IdentifiableSource source = synonym.getSources().iterator().next();
931
										if (source.getIdNamespace().contains("Potential combination")){
932
											acceptedTaxon.addSynonym(synonym, SynonymType.POTENTIAL_COMBINATION_OF());
933
											logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to potential combination");
934
										} else if (source.getIdNamespace().contains("Inferred Genus")){
935
											acceptedTaxon.addSynonym(synonym, SynonymType.INFERRED_GENUS_OF());
936
											logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to inferred genus");
937
										} else if (source.getIdNamespace().contains("Inferred Epithet")){
938
											acceptedTaxon.addSynonym(synonym, SynonymType.INFERRED_EPITHET_OF());
939
											logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to inferred epithet");
940
										} else{
941
											acceptedTaxon.addSynonym(synonym, SynonymType.INFERRED_SYNONYM_OF());
942
											logger.error(synonym.getTitleCache() + " is not attached to " + acceptedTaxon.getTitleCache() + " type is set to inferred synonym");
943
										}
944

    
945
										localSuccess &= synRelMapping.invoke(synonym);
946
										if (!localSuccess) {
947
											logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
948
										}
949
									} else {
950
										localSuccess &= synRelMapping.invoke(synonym);
951
										if (!localSuccess) {
952
											logger.error("Synonym relationship export failed " + synonym.getTitleCache() + " accepted taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
953
										} else {
954
											logger.info("Synonym relationship successfully exported: " + synonym.getTitleCache() + "  " +acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache()+")");
955
										}
956
									}
957

    
958
									inferredSynonymsDataToBeSaved.put(synonym.getId(), synonym.getName());
959
								}
960
							}
961
						}catch(Exception e){
962
							logger.error(e.getMessage());
963
							e.printStackTrace();
964
						}
965
					} else {
966
						logger.error("Classification is NULL. Inferred Synonyms could not be created for this Taxon: " + acceptedTaxon.getUuid() + " (" + acceptedTaxon.getTitleCache() + ")");
967
					}
968
				} else {
969
//							logger.error("TaxonName is not a ZoologicalName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
970
				}
971
			} else {
972
				logger.error("This TaxonBase is not a Taxon even though it should be: " + taxonBase.getUuid() + " (" + taxonBase.getTitleCache() + ")");
973
			}
974
		}
975
		taxonList = null;
976
		return inferredSynonymsDataToBeSaved;
977
	}
978

    
979

    
980
	/**
981
	 * Handles names that do not appear in taxa
982
	 * @param state
983
	 * @param mapping
984
	 * @return
985
	 */
986
	private boolean doNames(PesiExportState state, PesiExportMapping additionalSourceMapping)  throws SQLException {
987

    
988
		boolean success = true;
989
		if (! state.getConfig().isDoPureNames()){
990
			logger.info ("Ignore PHASE 1b: PureNames");
991
			return success;
992
		}
993

    
994
		try {
995
			PesiExportMapping mapping = getPureNameMapping(state);
996
			mapping.initialize(state);
997
			int count = 0;
998
			int pastCount = 0;
999
			List<NonViralName<?>> list;
1000
			success = true;
1001
			// Get the limit for objects to save within a single transaction.
1002
			int limit = state.getConfig().getLimitSave();
1003

    
1004

    
1005
			logger.info("PHASE 1b: Export Pure Names ...");
1006
			// Start transaction
1007
			TransactionStatus txStatus = startTransaction(true);
1008
			logger.info("Started new transaction for Pure Names. Fetching some " + pluralString + " (max: " + limit + ") ...");
1009

    
1010
			int partitionCount = 0;
1011
			while ((list = getNextPureNamePartition(null, limit, partitionCount++)) != null   ) {
1012

    
1013
				logger.info("Fetched " + list.size() + " names without taxa. Exporting...");
1014
				for (TaxonNameBase<?,?> taxonName : list) {
1015
					doCount(count++, modCount, pluralString);
1016
					success &= mapping.invoke(taxonName);
1017
					//additional source
1018
					if (taxonName.getNomenclaturalReference() != null || StringUtils.isNotBlank(taxonName.getNomenclaturalMicroReference() )){
1019
						additionalSourceMapping.invoke(taxonName);
1020
					}
1021
				}
1022

    
1023
				// Commit transaction
1024
				commitTransaction(txStatus);
1025
				logger.debug("Committed transaction.");
1026
				logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
1027
				pastCount = count;
1028

    
1029
				// Start transaction
1030
				txStatus = startTransaction(true);
1031
				logger.info("Started new transaction for PureNames. Fetching some " + pluralString + " (max: " + limit + ") ...");
1032
			}
1033
			if (list == null) {
1034
				logger.info("No " + pluralString + " left to fetch.");
1035
			}
1036
			list = null;
1037
			// Commit transaction
1038
			commitTransaction(txStatus);
1039
			logger.debug("Committed transaction.");
1040
		} catch (Exception e) {
1041
			logger.error("Error occurred in pure name export");
1042
			e.printStackTrace();
1043
			success = false;
1044
		}
1045
		return success;
1046
	}
1047

    
1048
	/**
1049
	 * Determines the current number of entries in the DataWarehouse database table <code>Taxon</code>.
1050
	 * @param state The {@link PesiExportState PesiExportState}.
1051
	 * @return The count.
1052
	 */
1053
	private Integer determineTaxonCount(PesiExportState state) {
1054
		Integer result = null;
1055
		PesiExportConfigurator pesiConfig = state.getConfig();
1056

    
1057
		String sql;
1058
		Source destination =  pesiConfig.getDestination();
1059
		sql = "SELECT max(taxonId) FROM Taxon";
1060
		destination.setQuery(sql);
1061
		ResultSet resultSet = destination.getResultSet();
1062
		try {
1063
			resultSet.next();
1064
			result = resultSet.getInt(1);
1065
		} catch (SQLException e) {
1066
			logger.error("TaxonCount could not be determined: " + e.getMessage());
1067
			e.printStackTrace();
1068
		}
1069
		resultSet = null;
1070
		return result;
1071
	}
1072

    
1073
	/**
1074
	 * Checks whether a parent at specific level has a specific Rank.
1075
	 * @param taxonName A {@link TaxonNameBase TaxonName}.
1076
	 * @param level The ancestor level.
1077
	 * @param ancestorRank The ancestor rank.
1078
	 * @return Whether a parent at a specific level has a specific Rank.
1079
	 */
1080
	private boolean validateAncestorOfSpecificRank(TaxonBase<?> taxonBase, int level, Rank ancestorRank) {
1081
		boolean result = false;
1082
		TaxonNode parentNode = null;
1083
		if (taxonBase.isInstanceOf(Taxon.class)){
1084
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1085
			// Get ancestor Taxon via TaxonNode
1086
			Set<TaxonNode> taxonNodes = taxon.getTaxonNodes();
1087
			if (taxonNodes.size() == 1) {
1088
				TaxonNode taxonNode = taxonNodes.iterator().next();
1089
				if (taxonNode != null) {
1090
					for (int i = 0; i < level; i++) {
1091
						if (taxonNode != null) {
1092
							taxonNode  = taxonNode.getParent();
1093
						}
1094
					}
1095
					parentNode = taxonNode;
1096
				}
1097
			} else if (taxonNodes.size() > 1) {
1098
				logger.error("This taxon has " + taxonNodes.size() + " taxonNodes: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1099
			}
1100
		}
1101
		//compare
1102
		if (parentNode != null) {
1103
			TaxonNode node = CdmBase.deproxy(parentNode, TaxonNode.class);
1104
			Taxon parentTaxon = node.getTaxon();
1105
			if (parentTaxon != null) {
1106
				TaxonNameBase<?,?> parentTaxonName = parentTaxon.getName();
1107
				if (parentTaxonName != null && parentTaxonName.getRank().equals(ancestorRank)) {
1108
					result = true;
1109
				}
1110
			} else if (parentNode.treeIndex().matches("#t\\d+#\\d+#")) {
1111
				//do nothing (is root node)
1112
			} else {
1113
				logger.error("This TaxonNode has no Taxon: " + node.getUuid());
1114
			}
1115
		}
1116
		return result;
1117
	}
1118

    
1119
	/**
1120
	 * Returns the AnnotationType for a given UUID.
1121
	 * @param uuid The Annotation UUID.
1122
	 * @param label The Annotation label.
1123
	 * @param text The Annotation text.
1124
	 * @param labelAbbrev The Annotation label abbreviation.
1125
	 * @return The AnnotationType.
1126
	 */
1127
	protected AnnotationType getAnnotationType(UUID uuid, String label, String text, String labelAbbrev){
1128
		AnnotationType annotationType = (AnnotationType)getTermService().find(uuid);
1129
		if (annotationType == null) {
1130
			annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);
1131
			annotationType.setUuid(uuid);
1132
//			annotationType.setVocabulary(AnnotationType.EDITORIAL().getVocabulary());
1133
			getTermService().save(annotationType);
1134
		}
1135
		return annotationType;
1136
	}
1137

    
1138
	/**
1139
	 * Traverses the classification recursively and stores determined values for every Taxon.
1140
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1141
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1142
	 * @param treeIndex The TreeIndex at the current level.
1143
	 * @param fetchLevel Rank to stop fetching at.
1144
	 * @param state The {@link PesiExportState PesiExportState}.
1145
	 */
1146
	private void traverseTree(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, Rank fetchLevel, PesiExportState state) {
1147
		// Traverse all branches from this childNode until specified fetchLevel is reached.
1148
		StringBuffer localTreeIndex = new StringBuffer(treeIndex);
1149
		Taxon childTaxon = childNode.getTaxon();
1150
		if (childTaxon != null) {
1151
			if (isPesiTaxon(childTaxon)){
1152
				Integer taxonId = state.getDbId(childTaxon);
1153
				TaxonNameBase<?,?> childName = childTaxon.getName();
1154
				if (taxonId != null) {
1155
					Rank childRank = childName.getRank();
1156
					if (childRank != null) {
1157
						if (! childRank.equals(fetchLevel)) {
1158

    
1159
							localTreeIndex.append(taxonId + "#");
1160

    
1161
							saveData(childNode, parentNode, localTreeIndex, state, taxonId);
1162

    
1163
							// Store treeIndex as annotation for further use
1164
							Annotation annotation = Annotation.NewInstance(localTreeIndex.toString(), getTreeIndexAnnotationType(), Language.DEFAULT());
1165
							childNode.addAnnotation(annotation);
1166

    
1167
							for (TaxonNode newNode : childNode.getChildNodes()) {
1168
								if (newNode.getTaxon() != null && isPesiTaxon(newNode.getTaxon())){
1169
									traverseTree(newNode, childNode, localTreeIndex, fetchLevel, state);
1170
								}
1171
							}
1172

    
1173
						} else {
1174
	//						logger.debug("Target Rank " + fetchLevel.getLabel() + " reached");
1175
							return;
1176
						}
1177
					} else {
1178
						logger.error("Rank is NULL. FetchLevel can not be checked: " + childName.getUuid() + " (" + childName.getTitleCache() + ")");
1179
					}
1180
				} else {
1181
					logger.error("Taxon can not be found in state: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
1182
				}
1183
			}else{
1184
				if (logger.isDebugEnabled()){
1185
					logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
1186
				}
1187
			}
1188

    
1189
		} else {
1190
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
1191
		}
1192
	}
1193

    
1194
	/**
1195
	 * Stores values in database for every recursive round.
1196
	 * @param childNode The {@link TaxonNode TaxonNode} to process.
1197
	 * @param parentNode The parent {@link TaxonNode TaxonNode} of the childNode.
1198
	 * @param treeIndex The TreeIndex at the current level.
1199
	 * @param state The {@link PesiExportState PesiExportState}.
1200
	 * @param currentTaxonFk The TaxonFk to store the values for.
1201
	 */
1202
	private void saveData(TaxonNode childNode, TaxonNode parentNode, StringBuffer treeIndex, PesiExportState state, Integer currentTaxonFk) {
1203
		// We are differentiating kingdoms by the nomenclatural code for now.
1204
		// This needs to be handled in a better way as soon as we know how to differentiate between more kingdoms.
1205
		Taxon childTaxon = childNode.getTaxon();
1206
		if (isPesiTaxon(childTaxon)) {
1207
			TaxonBase<?> parentTaxon = null;
1208
			if (parentNode != null) {
1209
				parentTaxon = parentNode.getTaxon();
1210

    
1211
			}
1212

    
1213
			invokeParentTaxonFkAndTreeIndex(state.getDbId(parentTaxon), currentTaxonFk,	treeIndex);
1214
		}
1215

    
1216
	}
1217

    
1218
	/**
1219
	 * Inserts values into the Taxon database table.
1220
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1221
	 * @param state The {@link PesiExportState PesiExportState}.
1222
	 * @param stmt The prepared statement.
1223
	 * @return Whether save was successful or not.
1224
	 */
1225
	protected boolean invokeParentTaxonFkAndTreeIndex(Integer parentTaxonFk, Integer currentTaxonFk, StringBuffer treeIndex) {
1226
		try {
1227
			if (parentTaxonFk != null) {
1228
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(1, parentTaxonFk);
1229
			} else {
1230
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(1, null);
1231
			}
1232

    
1233
			if (treeIndex != null) {
1234
				parentTaxonFk_TreeIndex_KingdomFkStmt.setString(2, treeIndex.toString());
1235
			} else {
1236
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(2, null);
1237
			}
1238

    
1239
			if (currentTaxonFk != null) {
1240
				parentTaxonFk_TreeIndex_KingdomFkStmt.setInt(3, currentTaxonFk);
1241
			} else {
1242
				parentTaxonFk_TreeIndex_KingdomFkStmt.setObject(3, null);
1243
			}
1244

    
1245
			parentTaxonFk_TreeIndex_KingdomFkStmt.executeUpdate();
1246
			return true;
1247
		} catch (SQLException e) {
1248
			logger.error("ParentTaxonFk (" + parentTaxonFk ==null? "-":parentTaxonFk + ") and TreeIndex could not be inserted into database for taxon "+ (currentTaxonFk == null? "-" :currentTaxonFk) + ": " + e.getMessage());
1249
			e.printStackTrace();
1250
			return false;
1251
		}
1252
	}
1253

    
1254
	protected boolean invokeParentTaxonFk(Integer parentId, Integer childId) {
1255
		try {
1256
			parentTaxonFkStmt.setInt(1, parentId);
1257
			parentTaxonFkStmt.setInt(2, childId);
1258
			parentTaxonFkStmt.executeUpdate();
1259
			return true;
1260
		} catch (SQLException e) {
1261
			logger.warn("ParentTaxonFk (" + parentId ==null? "-":parentId + ") could not be inserted into database for taxon "+ (childId == null? "-" :childId) + ": " + e.getMessage());
1262
			e.printStackTrace();
1263
			return false;
1264
		}
1265
	}
1266

    
1267

    
1268
	/**
1269
	 * Inserts Rank data and KingdomFk into the Taxon database table.
1270
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1271
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1272
	 * @param taxonFk The TaxonFk to store the values for.
1273
	 * @param state
1274
	 * @param kindomFk The KingdomFk.
1275
	 * @return Whether save was successful or not.
1276
	 */
1277
	private boolean invokeRankDataAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, Integer taxonFk, Integer kingdomFk, PesiExportState state) {
1278
		try {
1279
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1280
			if (rankFk != null) {
1281
				rankUpdateStmt.setInt(1, rankFk);
1282
			} else {
1283
				rankUpdateStmt.setObject(1, null);
1284
			}
1285

    
1286
			String rankCache = getRankCache(taxonName, nomenclaturalCode, state);
1287
			if (rankCache != null) {
1288
				rankUpdateStmt.setString(2, rankCache);
1289
			} else {
1290
				rankUpdateStmt.setObject(2, null);
1291
			}
1292

    
1293
			if (kingdomFk != null) {
1294

    
1295
				rankUpdateStmt.setInt(3, kingdomFk);
1296
			} else {
1297
				rankUpdateStmt.setObject(3, null);
1298
			}
1299

    
1300
			if (taxonFk != null) {
1301
				rankUpdateStmt.setInt(4, taxonFk);
1302
			} else {
1303
				rankUpdateStmt.setObject(4, null);
1304
			}
1305

    
1306
			rankUpdateStmt.executeUpdate();
1307
			return true;
1308
		} catch (SQLException e) {
1309
			logger.error("Data (RankFk, RankCache, KingdomFk) could not be inserted into database: " + e.getMessage());
1310
			e.printStackTrace();
1311
			return false;
1312
		}
1313
	}
1314

    
1315
	/**
1316
	 * Inserts Rank data, TypeNameFk, KingdomFk, expertFk and speciesExpertFk into the Taxon database table.
1317
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1318
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1319
	 * @param taxonFk The TaxonFk to store the values for.
1320
	 * @param typeNameFk The TypeNameFk.
1321
	 * @param state
1322
	 * @param kindomFk The KingdomFk.
1323
	 * @param expertFk The ExpertFk.
1324
	 * @param speciesExpertFk The SpeciesExpertFk.
1325
	 * @return Whether save was successful or not.
1326
	 */
1327
	private boolean invokeRankDataAndTypeNameFkAndKingdomFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode,
1328
			Integer taxonFk, Integer typeNameFk, Integer kingdomFkk, PesiExportState state) {
1329
		try {
1330
			int index = 1;
1331
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
1332
			if (rankFk != null) {
1333
				rankTypeExpertsUpdateStmt.setInt(index++, rankFk);
1334
			} else {
1335
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1336
			}
1337

    
1338
			String rankCache = getRankCache(taxonName, nomenclaturalCode, state);
1339
			if (rankCache != null) {
1340
				rankTypeExpertsUpdateStmt.setString(index++, rankCache);
1341
			} else {
1342
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1343
			}
1344

    
1345
			if (typeNameFk != null) {
1346
				rankTypeExpertsUpdateStmt.setInt(index++, typeNameFk);
1347
			} else {
1348
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1349
			}
1350

    
1351
			if (kingdomFkk != null) {
1352
				rankTypeExpertsUpdateStmt.setInt(index++, kingdomFkk);
1353
			} else {
1354
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1355
			}
1356

    
1357
//			if (expertFk != null) {
1358
//				rankTypeExpertsUpdateStmt.setInt(5, expertFk);
1359
//			} else {
1360
//				rankTypeExpertsUpdateStmt.setObject(5, null);
1361
//			}
1362
//
1363
//			//TODO handle experts GUIDS
1364
//			if (speciesExpertFk != null) {
1365
//				rankTypeExpertsUpdateStmt.setInt(6, speciesExpertFk);
1366
//			} else {
1367
//				rankTypeExpertsUpdateStmt.setObject(6, null);
1368
//			}
1369
//
1370
			if (taxonFk != null) {
1371
				rankTypeExpertsUpdateStmt.setInt(index++, taxonFk);
1372
			} else {
1373
				rankTypeExpertsUpdateStmt.setObject(index++, null);
1374
			}
1375

    
1376
			rankTypeExpertsUpdateStmt.executeUpdate();
1377
			return true;
1378
		} catch (SQLException e) {
1379
			logger.error("Data could not be inserted into database: " + e.getMessage());
1380
			e.printStackTrace();
1381
			return false;
1382
		} catch (Exception e) {
1383
			logger.error("Some exception occurred: " + e.getMessage());
1384
			e.printStackTrace();
1385
			return false;
1386
		}
1387
	}
1388

    
1389
	/**
1390
	 * Deletes all entries of database tables related to <code>Taxon</code>.
1391
	 * @param state The {@link PesiExportState PesiExportState}.
1392
	 * @return Whether the delete operation was successful or not.
1393
	 */
1394
	protected boolean doDelete(PesiExportState state) {
1395
		PesiExportConfigurator pesiConfig = state.getConfig();
1396

    
1397
		String sql;
1398
		Source destination =  pesiConfig.getDestination();
1399

    
1400
		// Clear Taxon
1401
		sql = "DELETE FROM " + dbTableName;
1402
		destination.setQuery(sql);
1403
		destination.update(sql);
1404
		return true;
1405
	}
1406

    
1407
	/* (non-Javadoc)
1408
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
1409
	 */
1410
	@Override
1411
	protected boolean isIgnore(PesiExportState state) {
1412
		return ! state.getConfig().isDoTaxa();
1413
	}
1414

    
1415

    
1416
	/**
1417
	 * Creates the kingdom fk.
1418
	 * @param taxonName
1419
	 * @return
1420
	 */
1421
	@SuppressWarnings("unused")  //used by mapper
1422
	private static Integer getKingdomFk(TaxonNameBase taxonName){
1423
		return PesiTransformer.nomenClaturalCode2Kingdom(taxonName.getNomenclaturalCode());
1424
	}
1425

    
1426
	/**
1427
	 * Creates the parent fk.
1428
	 * @param taxonName
1429
	 * @return
1430
	 */
1431
	@SuppressWarnings("unused")  //used by mapper
1432
	private static Integer getParentTaxonFk(TaxonBase<?> taxonBase, PesiExportState state){
1433
		if (taxonBase.isInstanceOf(Taxon.class)){
1434
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
1435
			if (! isMisappliedName(taxon)){
1436
				Set<TaxonNode> nodes = taxon.getTaxonNodes();
1437
				if (nodes.size() == 0){
1438
					if (taxon.getName().getRank().isLower(Rank.KINGDOM())){
1439
						logger.warn("Accepted taxon has no parent. " + taxon.getTitleCache() + ", " +  taxon.getUuid());
1440
					}
1441
				}else if (nodes.size() > 1){
1442
					logger.warn("Taxon has more than 1 node attached. This is not supported by PESI export." +  taxon.getTitleCache() + ", " +  taxon.getUuid());
1443
				}else{
1444
					Taxon parent =nodes.iterator().next().getParent().getTaxon();
1445
					return state.getDbId(parent);
1446
				}
1447
			}
1448
		}
1449
		return null;
1450
	}
1451

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

    
1463

    
1464
	/**
1465
	 * Returns the <code>RankFk</code> attribute.
1466
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1467
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1468
	 * @return The <code>RankFk</code> attribute.
1469
	 * @see MethodMapper
1470
	 */
1471
	private static Integer getRankFk(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode) {
1472
		Integer result = null;
1473
		try {
1474
			if (nomenclaturalCode != null) {
1475
				if (taxonName != null) {
1476
					if (taxonName.getRank() == null) {
1477
						logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1478
					} else {
1479
						result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1480
					}
1481
					if (result == null) {
1482
						logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1483
					}
1484
				}
1485
			}
1486
		} catch (Exception e) {
1487
			e.printStackTrace();
1488
		}
1489
		return result;
1490
	}
1491

    
1492
	/**
1493
	 * Returns the rank cache for the taxon name based on the names nomenclatural code.
1494
	 * You may not use this method for kingdoms other then Animalia, Plantae and Bacteria.
1495
	 * @param taxonName
1496
	 * @return
1497
	 */
1498
	@SuppressWarnings("unused")  //used by mapper
1499
	private static String getRankCache(TaxonNameBase<?,?> taxonName, PesiExportState state) {
1500
		return getRankCache(taxonName, taxonName.getNomenclaturalCode(), state);
1501
	}
1502

    
1503

    
1504
	/**
1505
	 * Returns the <code>RankCache</code> attribute.
1506
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1507
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
1508
	 * @param state
1509
	 * @return The <code>RankCache</code> attribute.
1510
	 * @see MethodMapper
1511
	 */
1512
	private static String getRankCache(TaxonNameBase<?,?> taxonName, NomenclaturalCode nomenclaturalCode, PesiExportState state) {
1513
		if (nomenclaturalCode != null) {
1514
			return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
1515
		}else{
1516
			logger.warn("No nomenclatural code defined for name " + taxonName.getUuid());
1517
			return null;
1518
		}
1519

    
1520
	}
1521

    
1522

    
1523
	/**
1524
	 * Returns the <code>DisplayName</code> attribute.
1525
	 * @param taxon The {@link TaxonBase Taxon}.
1526
	 * @return The <code>DisplayName</code> attribute.
1527
	 * @see MethodMapper
1528
	 */
1529
	@SuppressWarnings("unused")  //used by Mapper
1530
	private static String getDisplayName(TaxonBase<?> taxon) {
1531
		TaxonNameBase<?,?> taxonName = taxon.getName();
1532
		String result = getDisplayName(taxonName);
1533
		if (isMisappliedName(taxon)){
1534
			result = result + " " + getAuthorString(taxon);
1535
		}
1536
		return result;
1537
	}
1538

    
1539
	/**
1540
	 * Returns the <code>AuthorString</code> attribute.
1541
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1542
	 * @return The <code>AuthorString</code> attribute.
1543
	 * @see MethodMapper
1544
	 */
1545
	@SuppressWarnings("unused") //used by mapper
1546
	protected static String getAuthorString(TaxonBase<?> taxon) {
1547
		try {
1548
			String result = null;
1549
			boolean isNonViralName = false;
1550
			String authorshipCache = null;
1551
			TaxonNameBase<?,?> taxonName = taxon.getName();
1552
			if (taxonName != null && taxonName.isInstanceOf(NonViralName.class)){
1553
				authorshipCache = CdmBase.deproxy(taxonName, NonViralName.class).getAuthorshipCache();
1554
				isNonViralName = true;
1555
			}
1556
			result = authorshipCache;
1557

    
1558
			// For a misapplied names there are special rules
1559
			if (isMisappliedName(taxon)){
1560
				if (taxon.getSec() != null){
1561
					String secTitle = taxon.getSec().getTitleCache();
1562
					if (! secTitle.startsWith("auct")){
1563
						secTitle = "sensu " + secTitle;
1564
					}else if (secTitle.equals("auct")){  //may be removed once the title cache is generated correctly for references with title auct. #
1565
						secTitle = "auct.";
1566
					}
1567
					return secTitle;
1568
				}else if (StringUtils.isBlank(authorshipCache)) {
1569
					// Set authorshipCache to "auct."
1570
					result = PesiTransformer.AUCT_STRING;
1571
				}else{
1572
					result = PesiTransformer.AUCT_STRING;
1573
//					result = authorshipCache;
1574
				}
1575
			}
1576

    
1577
			if (taxonName == null){
1578
				logger.warn("TaxonName does not exist for taxon: " + taxon.getUuid() + " (" + taxon.getTitleCache() + ")");
1579
			}else if (! isNonViralName){
1580
				logger.warn("TaxonName is not of instance NonViralName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1581
			}
1582

    
1583
			if (StringUtils.isBlank(result)) {
1584
				return null;
1585
			} else {
1586
				return result;
1587
			}
1588
		} catch (Exception e) {
1589
			e.printStackTrace();
1590
			return null;
1591
		}
1592

    
1593
	}
1594

    
1595

    
1596
	/**
1597
	 * Returns the <code>DisplayName</code> attribute.
1598
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1599
	 * @return The <code>DisplayName</code> attribute.
1600
	 * @see MethodMapper
1601
	 */
1602
	@SuppressWarnings("unused")  //used by Mapper
1603
	private static String getDisplayName(TaxonNameBase<?,?> taxonName) {
1604
		// TODO: extension?
1605
		if (taxonName == null) {
1606
			return null;
1607
		}else{
1608
			INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1609
			HTMLTagRules tagRules = new HTMLTagRules().
1610
					addRule(TagEnum.name, "i").
1611
					addRule(TagEnum.nomStatus, "@status@");
1612

    
1613
			NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1614
			String result = cacheStrategy.getFullTitleCache(nvn, tagRules);
1615
			cacheStrategy = null;
1616
			nvn = null;
1617
			return result.replaceAll(",?\\<@status@\\>.*\\</@status@\\>", "");
1618
		}
1619
	}
1620

    
1621
	@SuppressWarnings("unused")
1622
	private static String getGUID(TaxonNameBase<?,?> taxonName) {
1623
		UUID uuid = taxonName.getUuid();
1624
		String result = "NameUUID:" + uuid.toString();
1625
		return result;
1626
	}
1627

    
1628

    
1629
	/**
1630
	 * Returns the <code>WebShowName</code> attribute for a taxon.
1631
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1632
	 * @return The <code>WebShowName</code> attribute.
1633
	 * @see MethodMapper
1634
	*/
1635
	@SuppressWarnings("unused")
1636
	private static String getWebShowName(TaxonBase<?> taxon) {
1637
		TaxonNameBase<?,?> taxonName = taxon.getName();
1638
		String result = getWebShowName(taxonName);
1639
		if (isMisappliedName(taxon)){
1640
			result = result + " " + getAuthorString(taxon);
1641
		}
1642
		return result;
1643
	}
1644

    
1645
	/**
1646
	 * Returns the <code>WebShowName</code> attribute.
1647
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1648
	 * @return The <code>WebShowName</code> attribute.
1649
	 * @see MethodMapper
1650
	 */
1651
	private static String getWebShowName(TaxonNameBase<?,?> taxonName) {
1652
		//TODO extensions?
1653
		if (taxonName == null) {
1654
			return null;
1655
		}else{
1656
			INonViralNameCacheStrategy<NonViralName<?>> cacheStrategy = getCacheStrategy(taxonName);
1657

    
1658
			HTMLTagRules tagRules = new HTMLTagRules().addRule(TagEnum.name, "i");
1659
			NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1660
			String result = cacheStrategy.getTitleCache(nvn, tagRules);
1661
			cacheStrategy = null;
1662
			nvn = null;
1663
			return result;
1664
		}
1665
	}
1666

    
1667

    
1668
	/**
1669
	 * Returns the <code>WebSearchName</code> attribute.
1670
	 * @param taxonName The {@link NonViralName NonViralName}.
1671
	 * @return The <code>WebSearchName</code> attribute.
1672
	 * @see MethodMapper
1673
	 */
1674
	@SuppressWarnings("unused")
1675
	private static String getWebSearchName(TaxonNameBase<?,?> taxonName) {
1676
		//TODO extensions?
1677
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1678
		NonViralNameDefaultCacheStrategy<NonViralName<?>> strategy = getCacheStrategy(nvn);
1679
		String result = strategy.getNameCache(nvn);
1680
		strategy = null;
1681
		nvn = null;
1682
		return result;
1683
	}
1684

    
1685

    
1686
	/**
1687
	 * Returns the <code>FullName</code> attribute.
1688
	 * @param taxonName The {@link NonViralName NonViralName}.
1689
	 * @return The <code>FullName</code> attribute.
1690
	 * @see MethodMapper
1691
	 */
1692
	@SuppressWarnings("unused")
1693
	private static String getFullName(TaxonNameBase taxonName) {
1694
		//TODO extensions?
1695
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1696
		String result = getCacheStrategy(nvn).getTitleCache(nvn);
1697
		Iterator<TaxonBase> taxa = taxonName.getTaxa().iterator();
1698
		if (taxonName.getTaxa().size() >0){
1699
			if (taxonName.getTaxa().size() == 1){
1700
				TaxonBase taxon = taxa.next();
1701
				if (isMisappliedName(taxon)){
1702
					result = result + " " + getAuthorString(taxon);
1703
				}
1704
				taxon = null;
1705
			}
1706
		}
1707
		taxa = null;
1708
		nvn = null;
1709
		return result;
1710
	}
1711

    
1712
	/**
1713
	 * Returns the SourceNameCache for the AdditionalSource table
1714
	 * @param taxonName
1715
	 * @return
1716
	 */
1717
	@SuppressWarnings("unused")
1718
	private static String getSourceNameCache(TaxonNameBase taxonName) {
1719
		NonViralName<?> nvn = CdmBase.deproxy(taxonName, NonViralName.class);
1720
		if (nvn != null){
1721
			Reference nomRef = (Reference)nvn.getNomenclaturalReference();
1722
			if (nomRef != null){
1723
			    logger.warn("Semantics of getAbbrevTitleCache has changed. Please check if output is still correct. See #5388");
1724
				return nomRef.getAbbrevTitleCache();
1725
			}
1726
		}
1727
		return null;
1728
	}
1729

    
1730

    
1731

    
1732
	/**
1733
	 * Returns the <code>FullName</code> attribute.
1734
	 * @param taxon The {@link TaxonBase taxon}.
1735
	 * @return The <code>FullName</code> attribute.
1736
	 * @see MethodMapper
1737
	 */
1738
	/*@SuppressWarnings("unused")
1739
	private static String getFullName(TaxonBase taxon) {
1740
		//TODO extensions?
1741
		TaxonNameBase name = taxon.getName();
1742
		String result = getFullName(name);
1743
		if (isMisappliedName(taxon)){
1744
			result = result + " " + getAuthorString(taxon);
1745
		}
1746

    
1747
		return result;
1748
	}
1749
*/
1750

    
1751
	/**
1752
	 * Returns the nomenclatural reference which is the reference
1753
	 * including the detail (microreference).
1754
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1755
	 * @return The <code>AuthorString</code> attribute.
1756
	 * @see MethodMapper
1757
	 */
1758
	@SuppressWarnings("unused")
1759
	private static String getNomRefString(TaxonNameBase<?,?> taxonName) {
1760
		INomenclaturalReference ref = taxonName.getNomenclaturalReference();
1761
		if (ref == null){
1762
			return null;
1763
		}
1764
		if (! ref.isProtectedAbbrevTitleCache()){
1765
			ref.setAbbrevTitleCache(null, false);  //to remove a false cache
1766
		}
1767
		return ref.getNomenclaturalCitation(taxonName.getNomenclaturalMicroReference());
1768
	}
1769

    
1770

    
1771
	/**
1772
	 * Returns the <code>NameStatusFk</code> attribute.
1773
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1774
	 * @return The <code>NameStatusFk</code> attribute.
1775
	 * @see MethodMapper
1776
	 */
1777
	@SuppressWarnings("unused")
1778
	private static Integer getNameStatusFk(TaxonNameBase<?,?> taxonName) {
1779
		Integer result = null;
1780

    
1781
		NomenclaturalStatus state = getNameStatus(taxonName);
1782
		if (state != null) {
1783
			result = PesiTransformer.nomStatus2nomStatusFk(state.getType());
1784
		}
1785
		return result;
1786
	}
1787

    
1788
	/**
1789
	 * Returns the <code>NameStatusCache</code> attribute.
1790
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1791
	 * @return The <code>NameStatusCache</code> attribute.
1792
	 * @throws UndefinedTransformerMethodException
1793
	 * @see MethodMapper
1794
	 */
1795
	@SuppressWarnings("unused")
1796
	private static String getNameStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1797
		String result = null;
1798
		NomenclaturalStatus status = getNameStatus(taxonName);
1799
		if (status != null) {
1800
			result = state.getTransformer().getCacheByNomStatus(status.getType());
1801
		}
1802
		return result;
1803
	}
1804

    
1805

    
1806
	private static NomenclaturalStatus getNameStatus(TaxonNameBase<?,?> taxonName) {
1807
		try {
1808
			if (taxonName != null && (taxonName.isInstanceOf(NonViralName.class))) {
1809
				NonViralName<?> nonViralName = CdmBase.deproxy(taxonName, NonViralName.class);
1810
				Set<NomenclaturalStatus> states = nonViralName.getStatus();
1811
				if (states.size() == 1) {
1812
					NomenclaturalStatus status = states.iterator().next();
1813
					return status;
1814
				} else if (states.size() > 1) {
1815
					logger.error("This TaxonName has more than one Nomenclatural Status: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1816
				}
1817
			}
1818

    
1819
		} catch (Exception e) {
1820
			e.printStackTrace();
1821
		}
1822
		return null;
1823
	}
1824
	/**
1825
	 * Returns the <code>TaxonStatusFk</code> attribute.
1826
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1827
	 * @param state The {@link PesiExportState PesiExportState}.
1828
	 * @return The <code>TaxonStatusFk</code> attribute.
1829
	 * @see MethodMapper
1830
	 */
1831
	private static Integer getTaxonStatusFk(TaxonBase<?> taxon, PesiExportState state) {
1832
		Integer result = null;
1833

    
1834
		try {
1835
			if (isMisappliedName(taxon)) {
1836
				Synonym synonym = Synonym.NewInstance(null, null);
1837

    
1838
				// This works as long as only the instance is important to differentiate between TaxonStatus.
1839
				result = PesiTransformer.taxonBase2statusFk(synonym); // Auct References are treated as Synonyms in Datawarehouse now.
1840
			} else {
1841
				result = PesiTransformer.taxonBase2statusFk(taxon);
1842
			}
1843

    
1844
		} catch (Exception e) {
1845
			e.printStackTrace();
1846
		}
1847
		return result;
1848
	}
1849

    
1850
	/**
1851
	 * Returns the <code>TaxonStatusCache</code> attribute.
1852
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1853
	 * @param state The {@link PesiExportState PesiExportState}.
1854
	 * @return The <code>TaxonStatusCache</code> attribute.
1855
	 * @throws UndefinedTransformerMethodException
1856
	 * @see MethodMapper
1857
	 */
1858
	@SuppressWarnings("unused")
1859
	private static String getTaxonStatusCache(TaxonBase<?> taxon, PesiExportState state) throws UndefinedTransformerMethodException {
1860
		return state.getTransformer().getTaxonStatusCacheByKey(getTaxonStatusFk(taxon, state));
1861
	}
1862

    
1863
	/**
1864
	 * Returns the <code>TypeNameFk</code> attribute.
1865
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1866
	 * @param state The {@link PesiExportState PesiExportState}.
1867
	 * @return The <code>TypeNameFk</code> attribute.
1868
	 * @see MethodMapper
1869
	 */
1870
	private static Integer getTypeNameFk(TaxonNameBase<?,?> taxonNameBase, PesiExportState state) {
1871
		Integer result = null;
1872
		if (taxonNameBase != null) {
1873
			Set<NameTypeDesignation> nameTypeDesignations = taxonNameBase.getNameTypeDesignations();
1874
			if (nameTypeDesignations.size() == 1) {
1875
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1876
				if (nameTypeDesignation != null) {
1877
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1878
					if (typeName != null) {
1879
						result = state.getDbId(typeName);
1880
					}
1881
				}
1882
			} else if (nameTypeDesignations.size() > 1) {
1883
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonNameBase.getUuid() + " (" + taxonNameBase.getTitleCache() + ")");
1884
			}
1885
		}
1886
		return result;
1887
	}
1888

    
1889
	/**
1890
	 * Returns the <code>TypeFullnameCache</code> attribute.
1891
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1892
	 * @return The <code>TypeFullnameCache</code> attribute.
1893
	 * @see MethodMapper
1894
	 */
1895
	@SuppressWarnings("unused")
1896
	private static String getTypeFullnameCache(TaxonNameBase<?,?> taxonName) {
1897
		String result = null;
1898

    
1899
		try {
1900
		if (taxonName != null) {
1901
			Set<NameTypeDesignation> nameTypeDesignations = taxonName.getNameTypeDesignations();
1902
			if (nameTypeDesignations.size() == 1) {
1903
				NameTypeDesignation nameTypeDesignation = nameTypeDesignations.iterator().next();
1904
				if (nameTypeDesignation != null) {
1905
					TaxonNameBase<?,?> typeName = nameTypeDesignation.getTypeName();
1906
					if (typeName != null) {
1907
						result = typeName.getTitleCache();
1908
					}
1909
				}
1910
			} else if (nameTypeDesignations.size() > 1) {
1911
				logger.warn("This TaxonName has " + nameTypeDesignations.size() + " NameTypeDesignations: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1912
			}
1913
		}
1914

    
1915
		} catch (Exception e) {
1916
			e.printStackTrace();
1917
		}
1918
		return result;
1919
	}
1920

    
1921

    
1922
	/**
1923
	 * Returns the <code>QualityStatusFk</code> attribute.
1924
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1925
	 * @return The <code>QualityStatusFk</code> attribute.
1926
	 * @see MethodMapper
1927
	 */
1928
	private static Integer getQualityStatusFk(TaxonNameBase taxonName) {
1929
		BitSet sources = getSources(taxonName);
1930
		return PesiTransformer.getQualityStatusKeyBySource(sources, taxonName);
1931
	}
1932

    
1933

    
1934
	/**
1935
	 * Returns the <code>QualityStatusCache</code> attribute.
1936
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1937
	 * @return The <code>QualityStatusCache</code> attribute.
1938
	 * @throws UndefinedTransformerMethodException
1939
	 * @see MethodMapper
1940
	 */
1941
	@SuppressWarnings("unused")
1942
	private static String getQualityStatusCache(TaxonNameBase taxonName, PesiExportState state) throws UndefinedTransformerMethodException {
1943
		return state.getTransformer().getQualityStatusCacheByKey(getQualityStatusFk(taxonName));
1944
	}
1945

    
1946

    
1947
	/**
1948
	 * Returns the <code>TypeDesignationStatusFk</code> attribute.
1949
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1950
	 * @return The <code>TypeDesignationStatusFk</code> attribute.
1951
	 * @see MethodMapper
1952
	 */
1953
	@SuppressWarnings("unused")
1954
	private static Integer getTypeDesignationStatusFk(TaxonNameBase<?,?> taxonName) {
1955
		Integer result = null;
1956

    
1957
		try {
1958
		if (taxonName != null) {
1959
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1960
			if (typeDesignations.size() == 1) {
1961
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1962
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1963
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusId(designationStatus);
1964
			} else if (typeDesignations.size() > 1) {
1965
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1966
			}
1967
		}
1968

    
1969
		} catch (Exception e) {
1970
			e.printStackTrace();
1971
		}
1972
		return result;
1973
	}
1974

    
1975
	/**
1976
	 * Returns the <code>TypeDesignationStatusCache</code> attribute.
1977
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
1978
	 * @return The <code>TypeDesignationStatusCache</code> attribute.
1979
	 * @see MethodMapper
1980
	 */
1981
	@SuppressWarnings("unused")
1982
	private static String getTypeDesignationStatusCache(TaxonNameBase<?,?> taxonName) {
1983
		String result = null;
1984

    
1985
		try {
1986
		if (taxonName != null) {
1987
			Set<NameTypeDesignation> typeDesignations = taxonName.getNameTypeDesignations();
1988
			if (typeDesignations.size() == 1) {
1989
				Object obj = typeDesignations.iterator().next().getTypeStatus();
1990
				NameTypeDesignationStatus designationStatus = CdmBase.deproxy(obj, NameTypeDesignationStatus.class);
1991
				result = PesiTransformer.nameTypeDesignationStatus2TypeDesignationStatusCache(designationStatus);
1992
			} else if (typeDesignations.size() > 1) {
1993
				logger.error("Found a TaxonName with more than one NameTypeDesignation: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
1994
			}
1995
		}
1996

    
1997
		} catch (Exception e) {
1998
			e.printStackTrace();
1999
		}
2000
		return result;
2001
	}
2002

    
2003
	/**
2004
	 * Returns the <code>FossilStatusFk</code> attribute.
2005
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2006
	 * @return The <code>FossilStatusFk</code> attribute.
2007
	 * @see MethodMapper
2008
	 */
2009
	@SuppressWarnings("unused")
2010
	private static Integer getFossilStatusFk(IdentifiableEntity<?> identEntity, PesiExportState state) {
2011
		Integer result = null;
2012

    
2013
		Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
2014
		if (fossilStatuus.size() == 0){
2015
			return null;
2016
		}else if (fossilStatuus.size() > 1){
2017
			logger.warn("More than 1 fossil status given for " +  identEntity.getTitleCache() + " " + identEntity.getUuid());
2018
		}
2019
		String fossilStatus = fossilStatuus.iterator().next();
2020

    
2021
		int statusFk = state.getTransformer().FossilStatusCache2FossilStatusFk(fossilStatus);
2022
		return statusFk;
2023
	}
2024

    
2025
	/**
2026
	 * Returns the <code>FossilStatusCache</code> attribute.
2027
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2028
	 * @return The <code>FossilStatusCache</code> attribute.
2029
	 * @see MethodMapper
2030
	 */
2031
	@SuppressWarnings("unused")
2032
	private static String getFossilStatusCache(IdentifiableEntity<?> identEntity, PesiExportState state) {
2033
		String result = null;
2034
		Set<String> fossilStatuus = identEntity.getExtensions(ErmsTransformer.uuidFossilStatus);
2035
		if (fossilStatuus.size() == 0){
2036
			return null;
2037
		}
2038
		for (String strFossilStatus : fossilStatuus){
2039
			result = CdmUtils.concat(";", result, strFossilStatus);
2040
		}
2041
		return result;
2042
	}
2043

    
2044
	/**
2045
	 * Returns the <code>IdInSource</code> attribute.
2046
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2047
	 * @return The <code>IdInSource</code> attribute.
2048
	 * @see MethodMapper
2049
	 */
2050
	@SuppressWarnings("unused")
2051
	private static String getIdInSource(IdentifiableEntity taxonName) {
2052
		String result = null;
2053

    
2054
		try {
2055
			Set<IdentifiableSource> sources = getPesiSources(taxonName);
2056
			if (sources.size() > 1){
2057
				logger.warn("There is > 1 Pesi source. This is not yet handled.");
2058
			}
2059
			if (sources.size() == 0){
2060
				logger.warn("There is no Pesi source!" +taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
2061
			}
2062
			for (IdentifiableSource source : sources) {
2063
				Reference ref = source.getCitation();
2064
				UUID refUuid = ref.getUuid();
2065
				String idInSource = source.getIdInSource();
2066
				if (refUuid.equals(BerlinModelTransformer.uuidSourceRefEuroMed)){
2067
					result = idInSource != null ? ("NameId: " + source.getIdInSource()) : null;
2068
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
2069
					result = idInSource != null ? ("TAX_ID: " + source.getIdInSource()) : null;
2070
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
2071
					result = idInSource != null ? ("tu_id: " + source.getIdInSource()) : null;
2072
				}else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){  //Index Fungorum
2073
					result = idInSource != null ? ("if_id: " + source.getIdInSource()) : null;
2074
				}else{
2075
					if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
2076
				}
2077

    
2078
				String sourceIdNameSpace = source.getIdNamespace();
2079
				if (sourceIdNameSpace != null) {
2080
					if (sourceIdNameSpace.equals(PesiTransformer.STR_NAMESPACE_NOMINAL_TAXON)) {
2081
						result =  idInSource != null ? ("Nominal Taxon from TAX_ID: " + source.getIdInSource()):null;
2082
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_EPITHET_NAMESPACE)) {
2083
						result =  idInSource != null ? ("Inferred epithet from TAX_ID: " + source.getIdInSource()) : null;
2084
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.INFERRED_GENUS_NAMESPACE)) {
2085
						result =  idInSource != null ? ("Inferred genus from TAX_ID: " + source.getIdInSource()):null;
2086
					} else if (sourceIdNameSpace.equals(TaxonServiceImpl.POTENTIAL_COMBINATION_NAMESPACE)) {
2087
						result =  idInSource != null ? ("Potential combination from TAX_ID: " + source.getIdInSource()):null;
2088
					}
2089
				}
2090
				if (result == null) {
2091
					logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +", sourceIdNameSpace: " + source.getIdNamespace()+")");
2092
				}
2093
			}
2094
		} catch (Exception e) {
2095
			e.printStackTrace();
2096
			logger.error("An error occurs while creating idInSource..." + taxonName.getUuid() + " (" + taxonName.getTitleCache()+ e.getMessage());
2097
		}
2098

    
2099
		if (result == null) {
2100
			logger.warn("IdInSource is NULL for this taxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() +")");
2101
		}
2102
		return result;
2103
	}
2104

    
2105
	/**
2106
	 * Returns the idInSource for a given TaxonName only.
2107
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2108
	 * @return The idInSource.
2109
	 */
2110
	private static String getIdInSourceOnly(IdentifiableEntity identEntity) {
2111
		String result = null;
2112

    
2113
		// Get the sources first
2114
		Set<IdentifiableSource> sources = getPesiSources(identEntity);
2115

    
2116
		// Determine the idInSource
2117
		if (sources.size() == 1) {
2118
			IdentifiableSource source = sources.iterator().next();
2119
			if (source != null) {
2120
				result = source.getIdInSource();
2121
			}
2122
		} else if (sources.size() > 1) {
2123
			int count = 1;
2124
			result = "";
2125
			for (IdentifiableSource source : sources) {
2126
				result += source.getIdInSource();
2127
				if (count < sources.size()) {
2128
					result += "; ";
2129
				}
2130
				count++;
2131
			}
2132

    
2133
		}
2134

    
2135
		return result;
2136
	}
2137

    
2138
	/**
2139
	 * Returns the Sources for a given TaxonName only.
2140
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2141
	 * @return The Sources.
2142
	 */
2143
	private static Set<IdentifiableSource> getPesiSources(IdentifiableEntity identEntity) {
2144
		Set<IdentifiableSource> sources = new java.util.HashSet<IdentifiableSource>();
2145

    
2146
		//Taxon Names
2147
		if (identEntity.isInstanceOf(TaxonNameBase.class)){
2148
			// Sources from TaxonName
2149
			TaxonNameBase taxonName = CdmBase.deproxy(identEntity, TaxonNameBase.class);
2150
			Set<IdentifiableSource> testSources = identEntity.getSources();
2151
			sources = filterPesiSources(identEntity.getSources());
2152

    
2153
			if (sources.size() == 0 && testSources.size()>0){
2154
				IdentifiableSource source = testSources.iterator().next();
2155
				logger.warn("There are sources, but they are no pesi sources!!!" + source.getIdInSource() + " - " + source.getIdNamespace() + " - " + source.getCitation().getTitleCache());
2156
			}
2157
			if (sources.size() > 1) {
2158
				logger.warn("This TaxonName has more than one Source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() + ")");
2159
			}
2160

    
2161
			// name has no PESI source, take sources from TaxonBase
2162
			if (sources == null || sources.isEmpty()) {
2163
				Set<TaxonBase> taxa = taxonName.getTaxonBases();
2164
				for (TaxonBase taxonBase: taxa){
2165
					sources.addAll(filterPesiSources(taxonBase.getSources()));
2166
				}
2167
			}
2168

    
2169
		//for TaxonBases
2170
		}else if (identEntity.isInstanceOf(TaxonBase.class)){
2171
			sources = filterPesiSources(identEntity.getSources());
2172
		}
2173

    
2174
		/*TODO: deleted only for testing the inferred synonyms
2175
		if (sources == null || sources.isEmpty()) {
2176
			logger.warn("This TaxonName has no PESI Sources: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2177
		}else if (sources.size() > 1){
2178
			logger.warn("This Taxon(Name) has more than 1 PESI source: " + identEntity.getUuid() + " (" + identEntity.getTitleCache() +")");
2179
		}
2180
		*/
2181
		return sources;
2182
	}
2183

    
2184
	// return all sources with a PESI reference
2185
	private static Set<IdentifiableSource> filterPesiSources(Set<? extends IdentifiableSource> sources) {
2186
		Set<IdentifiableSource> result = new HashSet<IdentifiableSource>();
2187
		for (IdentifiableSource source : sources){
2188
			Reference ref = source.getCitation();
2189
			UUID refUuid = ref.getUuid();
2190
			if (refUuid.equals(BerlinModelTransformer.uuidSourceRefEuroMed) ||
2191
				refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)||
2192
				refUuid.equals(PesiTransformer.uuidSourceRefErms)||
2193
				refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum) ||
2194
				refUuid.equals(PesiTransformer.uuidSourceRefAuct)){
2195
				result.add(source);
2196
			}
2197
		}
2198
		return result;
2199
	}
2200

    
2201
	/**
2202
	 * Returns the <code>GUID</code> attribute.
2203
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2204
	 * @return The <code>GUID</code> attribute.
2205
	 * @see MethodMapper
2206
	 */
2207
	private static String getGUID(TaxonBase<?> taxon) {
2208
		if (taxon.getLsid() != null ){
2209
			return taxon.getLsid().getLsid();
2210
		}else if (taxon.hasMarker(PesiTransformer.uuidMarkerGuidIsMissing, true)){
2211
			return null;
2212
		}else{
2213
			return taxon.getUuid().toString();
2214
		}
2215
	}
2216

    
2217

    
2218

    
2219

    
2220
	/**
2221
	 * Returns the <code>DerivedFromGuid</code> attribute.
2222
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2223
	 * @return The <code>DerivedFromGuid</code> attribute.
2224
	 * @see MethodMapper
2225
	 */
2226
	@SuppressWarnings("unused")
2227
	private static String getDerivedFromGuid(TaxonBase<?> taxon) {
2228
		String result = null;
2229
		try {
2230
		// The same as GUID for now
2231
		result = getGUID(taxon);
2232
		} catch (Exception e) {
2233
			e.printStackTrace();
2234
		}
2235
		return result;
2236
	}
2237

    
2238
	/**
2239
	 * Returns the <code>CacheCitation</code> attribute.
2240
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2241
	 * @return The CacheCitation.
2242
	 * @see MethodMapper
2243
	 */
2244
	@SuppressWarnings("unused")
2245
	private static String getCacheCitation(TaxonBase taxon) {
2246
		// !!! See also doPhaseUpdates
2247

    
2248
		TaxonNameBase<?,?> taxonName = taxon.getName();
2249
		String result = "";
2250
		//TODO implement anew for taxa
2251
		try {
2252
			BitSet sources = getSources(taxonName);
2253
			if (sources.isEmpty()) {
2254
//				logger.error("OriginalDB is NULL for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2255
			} else if (sources.get(PesiTransformer.SOURCE_ERMS)) {
2256
				// 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...
2257
				// 		 So the following code is some kind of harmless assumption.
2258
				Set<Extension> extensions = taxonName.getExtensions();
2259
				for (Extension extension : extensions) {
2260
					if (extension.getType().equals(cacheCitationExtensionType)) {
2261
						result = extension.getValue();
2262
					}
2263
				}
2264
			} else {
2265
				String expertName = getExpertName(taxon);
2266
				String webShowName = getWebShowName(taxonName);
2267

    
2268
				// idInSource only
2269
				String idInSource = getIdInSourceOnly(taxonName);
2270

    
2271
				// build the cacheCitation
2272
				if (expertName != null) {
2273
					result += expertName + ". ";
2274
				} else {
2275
					if (logger.isDebugEnabled()){logger.debug("ExpertName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");}
2276
				}
2277
				if (webShowName != null) {
2278
					result += webShowName + ". ";
2279
				} else {
2280
					logger.warn("WebShowName could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2281
				}
2282

    
2283
				if (getOriginalDB(taxonName).equals("FaEu")) {
2284
					result += "Accessed through: Fauna Europaea at http://faunaeur.org/full_results.php?id=";
2285
				} else if (getOriginalDB(taxonName).equals("EM")) {
2286
					result += "Accessed through: Euro+Med PlantBase at http://ww2.bgbm.org/euroPlusMed/PTaxonDetail.asp?UUID=";
2287
				}
2288

    
2289
				if (idInSource != null) {
2290
					result += idInSource;
2291
				} else {
2292
					logger.warn("IdInSource could not be determined for this TaxonName: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
2293
				}
2294
			}
2295
		} catch (Exception e) {
2296
			e.printStackTrace();
2297
		}
2298

    
2299
		if (StringUtils.isBlank(result)) {
2300
			return null;
2301
		} else {
2302
			return result;
2303
		}
2304
	}
2305

    
2306
	/**
2307
	 * Returns the <code>OriginalDB</code> attribute.
2308
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2309
	 * @return The <code>OriginalDB</code> attribute.
2310
	 * @see MethodMapper
2311
	 */
2312
	private static String getOriginalDB(IdentifiableEntity identEntity) {
2313
		// Sources from TaxonName
2314
		BitSet sources  = getSources(identEntity);
2315
		return PesiTransformer.getOriginalDbBySources(sources);
2316
	}
2317

    
2318
	/**
2319
	 * Returns the <code>LastAction</code> attribute.
2320
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2321
	 * @return The <code>LastAction</code> attribute.
2322
	 * @see MethodMapper
2323
	 */
2324
	@SuppressWarnings("unused")
2325
	private static String getLastAction(IdentifiableEntity<?> identEntity) {
2326
		String result = null;
2327
		try {
2328
		Set<Extension> extensions = identEntity.getExtensions();
2329
		for (Extension extension : extensions) {
2330
			if (extension.getType().equals(lastActionExtensionType)) {
2331
				result = extension.getValue();
2332
			}
2333
		}
2334
		} catch (Exception e) {
2335
			e.printStackTrace();
2336
		}
2337
		return result;
2338
	}
2339

    
2340
	/**
2341
	 * Returns the <code>LastActionDate</code> attribute.
2342
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2343
	 * @return The <code>LastActionDate</code> attribute.
2344
	 * @see MethodMapper
2345
	 */
2346
	@SuppressWarnings({ "unused" })
2347
	private static DateTime getLastActionDate(IdentifiableEntity identEntity) {
2348
		DateTime result = null;
2349
		try {
2350
			Set<Extension> extensions = identEntity.getExtensions();
2351
			for (Extension extension : extensions) {
2352
				if (extension.getType().equals(lastActionDateExtensionType)) {
2353
					String dateTime = extension.getValue();
2354
					if (dateTime != null) {
2355
						DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S");
2356
						result = formatter.parseDateTime(dateTime);
2357
					}
2358
				}
2359
			}
2360
		} catch (Exception e) {
2361
			e.printStackTrace();
2362
		}
2363
		return result;
2364
	}
2365

    
2366
	/**
2367
	 * Returns the <code>ExpertName</code> attribute.
2368
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2369
	 * @return The <code>ExpertName</code> attribute.
2370
	 * @see MethodMapper
2371
	 */
2372
	@SuppressWarnings("unused")
2373
	private static String getExpertName(TaxonBase<?> taxonName) {
2374
		String result = null;
2375
		try {
2376
		Set<Extension> extensions = taxonName.getExtensions();
2377
		for (Extension extension : extensions) {
2378
			if (extension.getType().equals(expertNameExtensionType)) {
2379
				result = extension.getValue();
2380
			}
2381
		}
2382
		} catch (Exception e) {
2383
			e.printStackTrace();
2384
		}
2385
		return result;
2386
	}
2387

    
2388
	/**
2389
	 * Returns the <code>ExpertFk</code> attribute.
2390
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2391
	 * @param state The {@link PesiExportState PesiExportState}.
2392
	 * @return The <code>ExpertFk</code> attribute.
2393
	 * @see MethodMapper
2394
	 */
2395
	private static Integer getExpertFk(Reference reference, PesiExportState state) {
2396
		Integer result = state.getDbId(reference);
2397
		return result;
2398
	}
2399

    
2400
	/**
2401
	 * Returns the <code>SpeciesExpertName</code> attribute.
2402
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
2403
	 * @return The <code>SpeciesExpertName</code> attribute.
2404
	 * @see MethodMapper
2405
	 */
2406
	@SuppressWarnings("unused")
2407
	private static String getSpeciesExpertName(TaxonBase<?> taxonName) {
2408
		String result = null;
2409
		try {
2410
		Set<Extension> extensions = taxonName.getExtensions();
2411
		for (Extension extension : extensions) {
2412
			if (extension.getType().equals(speciesExpertNameExtensionType)) {
2413
				result = extension.getValue();
2414
			}
2415
		}
2416
		} catch (Exception e) {
2417
			e.printStackTrace();
2418
		}
2419
		return result;
2420
	}
2421

    
2422
	/**
2423
	 * Returns the <code>SpeciesExpertFk</code> attribute.
2424
	 * @param reference The {@link Reference Reference}.
2425
	 * @param state The {@link PesiExportState PesiExportState}.
2426
	 * @return The <code>SpeciesExpertFk</code> attribute.
2427
	 * @see MethodMapper
2428
	 */
2429
	private static Integer getSpeciesExpertFk(Reference reference, PesiExportState state) {
2430
		Integer result = state.getDbId(reference);
2431
		return result;
2432
	}
2433

    
2434

    
2435
	/**
2436
	 * Returns the source (E+M, Fauna Europaea, Index Fungorum, ERMS) of a given
2437
	 * Identifiable Entity as a BitSet
2438
	 * @param identEntity
2439
	 * @return
2440
	 */
2441
	private static BitSet getSources(IdentifiableEntity<?> identEntity){
2442
		BitSet bitSet = new BitSet();
2443
		Set<IdentifiableSource> sources = getPesiSources(identEntity);
2444
		for (IdentifiableSource source : sources) {
2445
			Reference ref = source.getCitation();
2446
			UUID refUuid = ref.getUuid();
2447
			if (refUuid.equals(BerlinModelTransformer.uuidSourceRefEuroMed)){
2448
				bitSet.set(PesiTransformer.SOURCE_EM);
2449
			}else if (refUuid.equals(PesiTransformer.uuidSourceRefFaunaEuropaea)){
2450
				bitSet.set(PesiTransformer.SOURCE_FE);
2451
			}else if (refUuid.equals(PesiTransformer.uuidSourceRefErms)){
2452
				bitSet.set(PesiTransformer.SOURCE_ERMS);
2453
			}else if (refUuid.equals(PesiTransformer.uuidSourceRefIndexFungorum)){
2454
				bitSet.set(PesiTransformer.SOURCE_IF);
2455
			}else{
2456
				if (logger.isDebugEnabled()){logger.debug("Not a PESI source");};
2457
			}
2458
		}
2459
		return bitSet;
2460

    
2461
	}
2462

    
2463
	protected static NonViralNameDefaultCacheStrategy getCacheStrategy(TaxonNameBase<?, ?> taxonName) {
2464
		taxonName = CdmBase.deproxy(taxonName, TaxonNameBase.class);
2465
		NonViralNameDefaultCacheStrategy<?> cacheStrategy;
2466
		if (taxonName.isInstanceOf(ZoologicalName.class)){
2467
			cacheStrategy = zooNameStrategy;
2468
		}else if (taxonName.isInstanceOf(BotanicalName.class)) {
2469
			cacheStrategy = botanicalNameStrategy;
2470
		}else if (taxonName.getClass().equals(NonViralName.class)) {
2471
			cacheStrategy = nonViralNameStrategy;
2472
		}else if (taxonName.getClass().equals(BacterialName.class)) {
2473
			cacheStrategy = bacterialNameStrategy;
2474
		}else{
2475
			logger.error("Unhandled taxon name type. Can't define strategy class");
2476
			cacheStrategy = botanicalNameStrategy;
2477
		}
2478
		return cacheStrategy;
2479
	}
2480

    
2481
	/**
2482
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
2483
	 * @param relationship The {@link RelationshipBase Relationship}.
2484
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
2485
	 * @see MethodMapper
2486
	 */
2487
	@SuppressWarnings("unused")
2488
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
2489
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
2490
	}
2491
	/**
2492
	 * Returns the <code>Notes</code> attribute.
2493
	 * @param relationship The {@link RelationshipBase Relationship}.
2494
	 * @return The <code>Notes</code> attribute.
2495
	 * @see MethodMapper
2496
	 */
2497
	@SuppressWarnings("unused")
2498
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
2499
		// TODO
2500
		return null;
2501
	}
2502

    
2503

    
2504
	/**
2505
	 * Returns the CDM to PESI specific export mappings.
2506
	 * @return The {@link PesiExportMapping PesiExportMapping}.
2507
	 */
2508
	private PesiExportMapping getMapping() {
2509
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2510

    
2511
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2512
		mapping.addMapper(DbObjectMapper.NewInstance("sec", "sourceFk")); //OLD:mapping.addMapper(MethodMapper.NewInstance("SourceFK", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
2513
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusFk", this.getClass(), "getTaxonStatusFk", standardMethodParameter, PesiExportState.class));
2514
		mapping.addMapper(MethodMapper.NewInstance("TaxonStatusCache", this.getClass(), "getTaxonStatusCache", standardMethodParameter, PesiExportState.class));
2515

    
2516
		mapping.addMapper(MethodMapper.NewInstance("GUID", this));
2517

    
2518
		mapping.addMapper(MethodMapper.NewInstance("DerivedFromGuid", this));
2519
		mapping.addMapper(MethodMapper.NewInstance("CacheCitation", this));
2520
		mapping.addMapper(MethodMapper.NewInstance("AuthorString", this));  //For Taxon because Misallied Names are handled differently
2521
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this));
2522

    
2523
		// DisplayName
2524
		mapping.addMapper(MethodMapper.NewInstance("DisplayName", this));
2525

    
2526
		// FossilStatus (Fk, Cache)
2527
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusCache", this, IdentifiableEntity.class, PesiExportState.class));
2528
		mapping.addMapper(MethodMapper.NewInstance("FossilStatusFk", this, IdentifiableEntity.class, PesiExportState.class)); // PesiTransformer.FossilStatusCache2FossilStatusFk?
2529

    
2530
		//handled by name mapping
2531
		mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2532
		mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2533

    
2534
		//experts
2535
		ExtensionType extensionTypeSpeciesExpertName = (ExtensionType)getTermService().find(PesiTransformer.speciesExpertNameUuid);
2536
		mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeSpeciesExpertName, "SpeciesExpertName"));
2537
		ExtensionType extensionTypeExpertName = (ExtensionType)getTermService().find(PesiTransformer.expertNameUuid);
2538
		mapping.addMapper(DbExtensionMapper.NewInstance(extensionTypeExpertName, "ExpertName"));
2539

    
2540
//		mapping.addMapper(MethodMapper.NewInstance("ParentTaxonFk", this, TaxonBase.class, PesiExportState.class));  //by AM, doesn't work, FK exception
2541
		mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2542

    
2543
		addNameMappers(mapping);
2544

    
2545
		return mapping;
2546
	}
2547

    
2548
	/**
2549
	 * Returns the CDM to PESI specific export mappings.
2550
	 * @param state
2551
	 * @return The {@link PesiExportMapping PesiExportMapping}.
2552
	 * @throws UndefinedTransformerMethodException
2553
	 */
2554
	private PesiExportMapping getPureNameMapping(PesiExportState state) throws UndefinedTransformerMethodException {
2555
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
2556

    
2557
		mapping.addMapper(IdMapper.NewInstance("TaxonId"));
2558

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

    
2561
		mapping.addMapper(MethodMapper.NewInstance("KingdomFk", this, TaxonNameBase.class));
2562
		mapping.addMapper(MethodMapper.NewInstance("RankFk", this, TaxonNameBase.class));
2563
		mapping.addMapper(MethodMapper.NewInstance("RankCache", this, TaxonNameBase.class, PesiExportState.class));
2564
		mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusFk", Types.INTEGER , PesiTransformer.T_STATUS_UNACCEPTED));
2565
		mapping.addMapper(DbConstantMapper.NewInstance("TaxonStatusCache", Types.VARCHAR , state.getTransformer().getTaxonStatusCacheByKey( PesiTransformer.T_STATUS_UNACCEPTED)));
2566
		mapping.addMapper(DbStringMapper.NewInstance("AuthorshipCache", "AuthorString").setBlankToNull(true));
2567
		mapping.addMapper(MethodMapper.NewInstance("WebShowName", this, TaxonNameBase.class));
2568
		mapping.addMapper(MethodMapper.NewInstance("GUID", this, TaxonNameBase.class));
2569

    
2570

    
2571

    
2572
		// DisplayName
2573
		mapping.addMapper(MethodMapper.NewInstance("DisplayName", this, TaxonNameBase.class));
2574

    
2575
		mapping.addMapper(DbLastActionMapper.NewInstance("LastActionDate", false));
2576
		mapping.addMapper(DbLastActionMapper.NewInstance("LastAction", true));
2577

    
2578
		addNameMappers(mapping);
2579
		//TODO add author mapper, TypeNameFk
2580

    
2581
		return mapping;
2582
	}
2583

    
2584
	private void addNameMappers(PesiExportMapping mapping) {
2585
		mapping.addMapper(DbStringMapper.NewInstance("GenusOrUninomial", "GenusOrUninomial"));
2586
		mapping.addMapper(DbStringMapper.NewInstance("InfraGenericEpithet", "InfraGenericEpithet"));
2587
		mapping.addMapper(DbStringMapper.NewInstance("SpecificEpithet", "SpecificEpithet"));
2588
		mapping.addMapper(DbStringMapper.NewInstance("InfraSpecificEpithet", "InfraSpecificEpithet"));
2589

    
2590
//		mapping.addMapper(DbStringMapper.NewInstance("NameCache", "WebSearchName"));  //does not work as we need other cache strategy
2591
		mapping.addMapper(MethodMapper.NewInstance("WebSearchName", this, TaxonNameBase.class));
2592

    
2593
//		mapping.addMapper(DbStringMapper.NewInstance("TitleCache", "FullName"));    //does not work as we need other cache strategy
2594
		mapping.addMapper(MethodMapper.NewInstance("FullName", this, TaxonNameBase.class));
2595

    
2596

    
2597
		mapping.addMapper(MethodMapper.NewInstance("NomRefString", this, TaxonNameBase.class));
2598

    
2599
		mapping.addMapper(MethodMapper.NewInstance("NameStatusFk", this, TaxonNameBase.class));
2600
		mapping.addMapper(MethodMapper.NewInstance("NameStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2601
		mapping.addMapper(MethodMapper.NewInstance("TypeFullnameCache", this, TaxonNameBase.class));
2602
		//TODO TypeNameFk
2603

    
2604
		//quality status
2605
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusFk", this, TaxonNameBase.class));
2606
		mapping.addMapper(MethodMapper.NewInstance("QualityStatusCache", this, TaxonNameBase.class, PesiExportState.class));
2607

    
2608
		mapping.addMapper(MethodMapper.NewInstance("IdInSource", this, IdentifiableEntity.class));
2609
		mapping.addMapper(MethodMapper.NewInstance("OriginalDB", this, IdentifiableEntity.class) );
2610

    
2611
		//mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
2612

    
2613
	}
2614

    
2615
	private PesiExportMapping getSynRelMapping() {
2616
		PesiExportMapping mapping = new PesiExportMapping(dbTableNameSynRel);
2617

    
2618
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", RelationshipBase.class, PesiExportState.class));
2619
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", RelationshipBase.class, PesiExportState.class));
2620
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this,  RelationshipBase.class));
2621
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
2622
		mapping.addMapper(MethodMapper.NewInstance("Notes", this,  RelationshipBase.class));
2623

    
2624
		return mapping;
2625
	}
2626

    
2627
	private PesiExportMapping getAdditionalSourceMapping(PesiExportState state)  throws UndefinedTransformerMethodException{
2628
		PesiExportMapping mapping = new PesiExportMapping(dbTableAdditionalSourceRel);
2629

    
2630
		mapping.addMapper(IdMapper.NewInstance("TaxonFk"));
2631
		mapping.addMapper(ObjectChangeMapper.NewInstance(TaxonBase.class, TaxonNameBase.class, "Name"));
2632

    
2633
		mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceFk"));
2634
//		mapping.addMapper(DbObjectMapper.NewInstance("NomenclaturalReference", "SourceNameCache", IS_CACHE));
2635
		mapping.addMapper(MethodMapper.NewInstance("SourceNameCache", this, TaxonNameBase.class));
2636

    
2637

    
2638
		//we have only nomenclatural references here
2639
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER , PesiTransformer.NOMENCLATURAL_REFERENCE));
2640
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, state.getTransformer().getSourceUseCacheByKey( PesiTransformer.NOMENCLATURAL_REFERENCE)));
2641

    
2642
		mapping.addMapper(DbStringMapper.NewInstance("NomenclaturalMicroReference", "SourceDetail"));
2643

    
2644
		return mapping;
2645
	}
2646

    
2647
}
(11-11/12)