Project

General

Profile

Download (27.5 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.SQLException;
14
import java.util.ArrayList;
15
import java.util.HashMap;
16
import java.util.List;
17
import java.util.Set;
18

    
19
import org.apache.log4j.Logger;
20
import org.springframework.stereotype.Component;
21
import org.springframework.transaction.TransactionStatus;
22

    
23
import eu.etaxonomy.cdm.io.common.Source;
24
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
25
import eu.etaxonomy.cdm.model.common.CdmBase;
26
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
27
import eu.etaxonomy.cdm.model.common.RelationshipBase;
28
import eu.etaxonomy.cdm.model.name.HybridRelationship;
29
import eu.etaxonomy.cdm.model.name.NameRelationship;
30
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
31
import eu.etaxonomy.cdm.model.name.Rank;
32
import eu.etaxonomy.cdm.model.name.TaxonName;
33
import eu.etaxonomy.cdm.model.taxon.Classification;
34
import eu.etaxonomy.cdm.model.taxon.Synonym;
35
import eu.etaxonomy.cdm.model.taxon.Taxon;
36
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
37
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
38
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
39

    
40
/**
41
 * The export class for relations between {@link eu.etaxonomy.cdm.model.taxon.TaxonBase TaxonBases}.<p>
42
 * Inserts into DataWarehouse database table <code>RelTaxon</code>.
43
 * @author e.-m.lee
44
 * @date 23.02.2010
45
 *
46
 */
47
@Component
48
public class PesiRelTaxonExport extends PesiExportBase {
49

    
50
    private static final long serialVersionUID = 67808745337549629L;
51
    private static final Logger logger = Logger.getLogger(PesiRelTaxonExport.class);
52

    
53
    private static final Class<? extends CdmBase> standardMethodParameter = RelationshipBase.class;
54

    
55
	private static int modCount = 1000;
56
	private static final String dbTableName = "RelTaxon";
57
	private static final String pluralString = "Relationships";
58
	private static PreparedStatement synonymsStmt;
59

    
60
	private final HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();
61
	private final List<Rank> rankList = new ArrayList<Rank>();
62
	private PesiExportMapping mapping;
63
	private int count = 0;
64

    
65
	public PesiRelTaxonExport() {
66
		super();
67
	}
68

    
69
	@Override
70
	public Class<? extends CdmBase> getStandardMethodParameter() {
71
		return standardMethodParameter;
72
	}
73

    
74
	@Override
75
	protected boolean doCheck(PesiExportState state) {
76
		boolean result = true;
77
		return result;
78
	}
79

    
80
	@Override
81
	protected void doInvoke(PesiExportState state) {
82
		try {
83
			logger.info("*** Started Making " + pluralString + " ...");
84

    
85
			Connection connection = state.getConfig().getDestination().getConnection();
86
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?";
87
			synonymsStmt = connection.prepareStatement(synonymsSql);
88

    
89
			// Stores whether this invoke was successful or not.
90
			boolean success = true;
91

    
92
			// PESI: Clear the database table RelTaxon.
93
			//doDelete(state); -> done by stored procedure
94

    
95
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
96
			mapping = getMapping();
97

    
98
			// Initialize the db mapper
99
			mapping.initialize(state);
100

    
101
			//Export taxon relations
102
			success &= doPhase01(state, mapping);
103

    
104

    
105
			// Export name relations
106
			success &= doPhase02(state, mapping);
107

    
108
			if (! success){
109
				state.getResult().addError("An unknown error occurred in PesiRelTaxonExport");
110
			}
111

    
112
		} catch (SQLException e) {
113
			e.printStackTrace();
114
			logger.error(e.getMessage());
115
			state.getResult().addException(e);
116
			return;
117
		}
118
	}
119

    
120

    
121
	private boolean doPhase01(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
122
		logger.info("PHASE 1: Taxon Relationships ...");
123
		boolean success = true;
124

    
125
		int limit = state.getConfig().getLimitSave();
126
		// Start transaction
127
		TransactionStatus txStatus = startTransaction(true);
128
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
129

    
130
		List<RelationshipBase> list;
131

    
132
		//taxon relations
133
		int partitionCount = 0;
134
		int totalCount = 0;
135
		while ((list = getNextTaxonRelationshipPartition( limit, partitionCount++, null)) != null ) {
136
			totalCount = totalCount + list.size();
137
			logger.info("Read " + list.size() + " PESI relations. Limit: " + limit + ". Total: " + totalCount );
138
//			if (list.size() > 0){
139
//				logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
140
//			}
141
			for (RelationshipBase rel : list){
142
				try {
143
					mapping.invoke(rel);
144
				} catch (Exception e) {
145
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
146
					e.printStackTrace();
147
				}
148
			}
149

    
150
			commitTransaction(txStatus);
151
			txStatus = startTransaction();
152
		}
153
		list = null;
154
		commitTransaction(txStatus);
155
		return success;
156
	}
157

    
158
	private boolean doPhase02(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
159
		logger.info("PHASE 2: Name Relationships ...");
160
		boolean success = true;
161

    
162
		int limit = state.getConfig().getLimitSave();
163
		// Start transaction
164
		TransactionStatus txStatus = startTransaction(true);
165
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
166

    
167
		List<RelationshipBase> list;
168

    
169
		//name relations
170
		int partitionCount = 0;
171
		while ((list = getNextNameRelationshipPartition(null, limit, partitionCount++, null)) != null   ) {
172
			for (RelationshipBase rel : list){
173
				try {
174
				    TaxonName name1;
175
				    TaxonName name2;
176
					if (rel.isInstanceOf(HybridRelationship.class)){
177
						HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
178
						name1 = hybridRel.getParentName();
179
						name2 = hybridRel.getHybridName();
180
						hybridRel = null;
181
					}else if (rel.isInstanceOf(NameRelationship.class)){
182
						NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
183
						name1 = nameRel.getFromName();
184
						name2 = nameRel.getToName();
185
						nameRel = null;
186
					}else{
187
						logger.warn ("Only hybrid- and name-relationships alowed here");
188
						continue;
189
					}
190
					List<IdentifiableEntity> fromList = new ArrayList<IdentifiableEntity>();
191
					List<IdentifiableEntity> toList = new ArrayList<IdentifiableEntity>();
192
					makeList(name1, fromList);
193
					makeList(name2, toList);
194

    
195
					for (IdentifiableEntity fromEntity : fromList){
196
						for (IdentifiableEntity toEntity : toList){
197
							//TODO set entities to state
198
							state.setCurrentFromObject(fromEntity);
199
							state.setCurrentToObject(toEntity);
200
							mapping.invoke(rel);
201
						}
202
					}
203
					fromList = null;
204
					toList = null;
205
					name1 = null;
206
					name2 = null;
207
					rel = null;
208

    
209

    
210
				} catch (Exception e) {
211
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
212
					e.printStackTrace();
213
				}
214
			}
215
			commitTransaction(txStatus);
216
			txStatus = startTransaction();
217
		}
218
		commitTransaction(txStatus);
219
		list = null;
220
		logger.info("End PHASE 2: Name Relationships ...");
221
		state.setCurrentFromObject(null);
222
		state.setCurrentToObject(null);
223
		return success;
224
	}
225

    
226
	private void makeList(TaxonName name, List<IdentifiableEntity> list) {
227
		if (! hasPesiTaxon(name)){
228
			list.add(name);
229
		}else{
230
			for (TaxonBase taxon:  getPesiTaxa(name)){
231
				list.add(taxon);
232
			}
233
		}
234
	}
235

    
236
	/* (non-Javadoc)
237
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
238
	 */
239
	protected void doInvoke_Old(PesiExportState state) {
240
		try {
241
			logger.info("*** Started Making " + pluralString + " ...");
242

    
243
			Connection connection = state.getConfig().getDestination().getConnection();
244
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?";
245
			synonymsStmt = connection.prepareStatement(synonymsSql);
246

    
247
			// Stores whether this invoke was successful or not.
248
			boolean success = true;
249

    
250
			// PESI: Clear the database table RelTaxon.
251
			doDelete(state);
252

    
253
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
254
			mapping = getMapping();
255

    
256
			// Initialize the db mapper
257
			mapping.initialize(state);
258

    
259
			TransactionStatus txStatus = null;
260
			List<Classification> classificationList = null;
261

    
262
			// Specify starting ranks for tree traversing
263
			rankList.add(Rank.KINGDOM());
264
			rankList.add(Rank.GENUS());
265

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

    
270
			// Retrieve list of classifications
271
			txStatus = startTransaction(true);
272
			logger.info("Started transaction. Fetching all classifications...");
273
			classificationList = getClassificationService().listClassifications(null, 0, null, null);
274
			commitTransaction(txStatus);
275
			logger.debug("Committed transaction.");
276

    
277
			logger.info("Fetched " + classificationList.size() + " classification(s).");
278

    
279
			for (Classification classification : classificationList) {
280
				for (Rank rank : rankList) {
281

    
282
					txStatus = startTransaction(true);
283
					logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
284

    
285
					List<TaxonNode> rankSpecificRootNodes = getClassificationService().listRankSpecificRootNodes(classification, rank, null, null, null);
286
					logger.info("Fetched " + rankSpecificRootNodes.size() + " RootNodes for Rank " + rank.getLabel());
287

    
288
					commitTransaction(txStatus);
289
					logger.debug("Committed transaction.");
290

    
291
					for (TaxonNode rootNode : rankSpecificRootNodes) {
292
						txStatus = startTransaction(false);
293
						Rank endRank = rank2endRankMap.get(rank);
294
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till " + (endRank == null ? "leaves are reached ..." : "Rank " + endRank.getLabel() + " ..."));
295

    
296
						TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
297

    
298
						if (isPesiTaxon(newNode.getTaxon())){
299

    
300
							TaxonNode parentNode = newNode.getParent();
301

    
302
							success &=traverseTree(newNode, parentNode, endRank, state);
303

    
304
							commitTransaction(txStatus);
305
							logger.debug("Committed transaction.");
306
						}else{
307
							logger.debug("Taxon is not in PESI");
308
						}
309

    
310
					}
311
				}
312
			}
313

    
314
			logger.warn("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
315

    
316
			if (!success){
317
				state.getResult().addError("An unknown error occurred in PesiRelTaxonExport");
318
			}
319
			return;
320
		} catch (SQLException e) {
321
			e.printStackTrace();
322
			logger.error(e.getMessage());
323
			state.getResult().addException(e);
324
			return;
325
		}
326
	}
327

    
328
	/**
329
	 * Traverses the classification recursively and stores determined values for every Taxon.
330
	 * @param childNode
331
	 * @param parentNode
332
	 * @param treeIndex
333
	 * @param fetchLevel
334
	 * @param state
335
	 */
336
	private boolean  traverseTree(TaxonNode childNode, TaxonNode parentNode, Rank fetchLevel, PesiExportState state) {
337
		boolean success = true;
338
		// Traverse all branches from this childNode until specified fetchLevel is reached.
339
		TaxonBase<?> childTaxon = childNode.getTaxon();
340
		if (childTaxon != null) {
341
			if (isPesiTaxon(childTaxon)){
342
				if (childTaxon.getName() != null) {
343
					Rank childTaxonNameRank = childTaxon.getName().getRank();
344
					if (childTaxonNameRank != null) {
345
						if (! childTaxonNameRank.equals(fetchLevel)) {
346

    
347
							success &= saveData(childNode, parentNode, state);
348

    
349
							for (TaxonNode newNode : childNode.getChildNodes()) {
350
								success &= traverseTree(newNode, childNode, fetchLevel, state);
351
							}
352

    
353
						} else {
354
	//						logger.error("Target Rank " + fetchLevel.getLabel() + " reached");
355
							return success;
356
						}
357
					} else {
358
						logger.warn("Rank is NULL. FetchLevel can not be checked: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
359
					}
360
				} else {
361
					logger.error("TaxonName is NULL for taxon: " + childTaxon.getUuid());
362
				}
363
			}else{
364
				logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
365
			}
366

    
367
		} else {
368
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
369
		}
370
		return success;
371
	}
372

    
373
	/**
374
	 * Stores values in database for every recursive round.
375
	 * @param childNode
376
	 * @param parentNode
377
	 * @param treeIndex
378
	 * @param state
379
	 * @param currentTaxonFk
380
	 */
381
	private boolean saveData(TaxonNode childNode, TaxonNode parentNode, PesiExportState state) {
382
		boolean success = true;
383
		Taxon childNodeTaxon = childNode.getTaxon();
384
		if (childNodeTaxon != null) {
385
			// TaxonRelationships
386
			success &= saveTaxonRelationships(state, childNodeTaxon);
387
			// TaxonNameRelationships
388
			success &= saveNameRelationships(state, childNodeTaxon);
389
			// SynonymRelationships
390
			success &= saveSynonymAndSynNameRelationships(state, childNodeTaxon);
391
		}
392
		return success;
393

    
394
	}
395

    
396
	private boolean saveSynonymAndSynNameRelationships(PesiExportState state, Taxon childNodeTaxon) {
397
		boolean success = true;
398
		for (Synonym synonym : childNodeTaxon.getSynonyms()) { // synonyms of accepted taxon
399
		    TaxonName synonymTaxonName = synonym.getName();
400
			if (! isPesiTaxon(synonym)){
401
				logger.warn("Synonym " + synonym.getId() + " is not a PESI taxon. Can't export relationship");
402
				continue;
403
			}
404

    
405
			// Store synonym data in Taxon table
406
			invokeSynonyms(state, synonymTaxonName);
407

    
408

    
409
			try {
410
				if (neededValuesNotNull(synonym, state)) {
411
					doCount(count++, modCount, pluralString);
412
					success &= mapping.invoke(synonym);
413

    
414
				}
415
			} catch (SQLException e) {
416
				logger.error("Synonym (" + synonym.getUuid() + ") could not be stored : " + e.getMessage());
417
			}
418

    
419

    
420
			// SynonymNameRelationship
421
			success &= saveNameRelationships(state, synonym);
422
		}
423
		state.setCurrentFromObject(null);
424
		return success;
425
	}
426

    
427
	private boolean saveNameRelationships(PesiExportState state, TaxonBase taxonBase) {
428
		boolean success = true;
429
		TaxonName childNodeTaxonName = taxonBase.getName();
430

    
431
		//from relations
432
		Set<NameRelationship> nameRelations = childNodeTaxonName.getRelationsFromThisName();
433
		state.setCurrentFromObject(taxonBase);
434
		boolean isFrom = true;
435
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
436

    
437
		//toRelations
438
		nameRelations = childNodeTaxonName.getRelationsToThisName();
439
		state.setCurrentToObject(taxonBase);
440
		isFrom = false;
441
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
442
		state.setCurrentToObject(null);
443
		return success;
444
	}
445

    
446
	private boolean saveOneSideNameRelation(PesiExportState state, boolean isFrom, Set<NameRelationship> nameRelations) {
447
		boolean success = true;
448
		for (NameRelationship nameRelation : nameRelations) {
449
			try {
450
			    TaxonName relatedName = isFrom ? nameRelation.getToName(): nameRelation.getFromName();
451
				if ( isPurePesiName(relatedName)){
452
					success &= checkAndInvokeNameRelation(state, nameRelation, relatedName, isFrom);
453
				}else{
454
					for (TaxonBase<?> relatedTaxon : getPesiTaxa(relatedName)){
455
						success &= checkAndInvokeNameRelation(state, nameRelation, relatedTaxon, isFrom);
456
					}
457
				}
458
			} catch (SQLException e) {
459
				logger.error("NameRelationship " + nameRelation.getUuid() + " for " + nameRelation.getFromName().getTitleCache() + " and " + nameRelation.getToName().getTitleCache() + " could not be created: " + e.getMessage());
460
				success = false;
461
			}
462
		}
463
		return success;
464
	}
465

    
466
	private boolean checkAndInvokeNameRelation(PesiExportState state, NameRelationship nameRelation, IdentifiableEntity<?> relatedObject, boolean isFrom) throws SQLException {
467
		boolean success = true;
468
		if (isFrom){
469
			state.setCurrentToObject(relatedObject);
470
		}else{
471
			state.setCurrentFromObject(relatedObject);
472
		}
473
		if (neededValuesNotNull(nameRelation, state)) {
474
			doCount(count++, modCount, pluralString);
475
			success &= mapping.invoke(nameRelation);
476
		}
477
		state.setCurrentFromObject(null);
478
		state.setCurrentToObject(null);
479
		return success;
480
	}
481

    
482
	private boolean saveTaxonRelationships(PesiExportState state, Taxon childNodeTaxon) {
483
		boolean success = true;
484
		Taxon taxon = childNodeTaxon;
485
		Set<TaxonRelationship> taxonRelations = taxon.getRelationsToThisTaxon();
486
		for (TaxonRelationship taxonRelationship : taxonRelations) {
487
			try {
488
				if (neededValuesNotNull(taxonRelationship, state)) {
489
					doCount(count++, modCount, pluralString);
490
					success &= mapping.invoke(taxonRelationship);
491
				}
492
			} catch (SQLException e) {
493
				logger.error("TaxonRelationship could not be created for this TaxonRelation (" + taxonRelationship.getUuid() + "): " + e.getMessage());
494
			}
495
		}
496
		return success;
497
	}
498

    
499
	/**
500
	 * Determines synonym related data and saves them.
501
	 * @param state
502
	 * @param sr
503
	 */
504
	private void invokeSynonyms(PesiExportState state, TaxonName synonymTaxonName) {
505
		// Store KingdomFk and Rank information in Taxon table
506
		Integer kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(synonymTaxonName.getNomenclaturalCode());
507
		Integer synonymFk = state.getDbId(synonymTaxonName);
508

    
509
		saveSynonymData(state, synonymTaxonName, synonymTaxonName.getNomenclaturalCode(), kingdomFk, synonymFk);
510
	}
511

    
512
	/**
513
	 * Stores synonym data.
514
	 * @param state
515
	 * @param taxonName
516
	 * @param nomenclaturalCode
517
	 * @param kingdomFk
518
	 * @param synonymParentTaxonFk
519
	 * @param currentTaxonFk
520
	 */
521
	private boolean saveSynonymData(PesiExportState state, TaxonName taxonName,
522
			NomenclaturalCode nomenclaturalCode, Integer kingdomFk,
523
			Integer currentSynonymFk) {
524
		try {
525
			if (kingdomFk != null) {
526
				synonymsStmt.setInt(1, kingdomFk);
527
			} else {
528
				synonymsStmt.setObject(1, null);
529
			}
530

    
531
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
532
			if (rankFk != null) {
533
				synonymsStmt.setInt(2, rankFk);
534
			} else {
535
				synonymsStmt.setObject(2, null);
536
			}
537
			synonymsStmt.setString(3, getRankCache(taxonName, nomenclaturalCode, state));
538

    
539
			if (currentSynonymFk != null) {
540
				synonymsStmt.setInt(4, currentSynonymFk);
541
			} else {
542
				synonymsStmt.setObject(4, null);
543
			}
544
			synonymsStmt.executeUpdate();
545
			return true;
546
		} catch (SQLException e) {
547
			logger.error("SQLException during invoke for taxonName - " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + "): " + e.getMessage());
548
			e.printStackTrace();
549
			return false;
550
		}
551
	}
552

    
553
	private boolean neededValuesNotNull(Synonym synonym, PesiExportState state) {
554
	    boolean result = true;
555
        if (getTaxonFk1(synonym, state) == null) {
556
            logger.warn("TaxonFk1 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + synonym.getUuid());
557
            result = false;
558
        }
559
        return result;
560
	}
561

    
562

    
563
	/**
564
	 * Checks whether needed values for an entity are NULL.
565
	 * @return
566
	 */
567
	private boolean neededValuesNotNull(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
568
		boolean result = true;
569
		if (getTaxonFk1(relationship, state) == null) {
570
			logger.warn("TaxonFk1 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
571
			result = false;
572
		}
573
		if (getTaxonFk2(relationship, state) == null) {
574
			logger.warn("TaxonFk2 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
575
			result = false;
576
		}
577
		return result;
578
	}
579

    
580
	/**
581
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
582
	 * @param state The {@link PesiExportState PesiExportState}.
583
	 * @return Whether the delete operation was successful or not.
584
	 */
585
	protected boolean doDelete(PesiExportState state) {
586
		PesiExportConfigurator pesiConfig = state.getConfig();
587

    
588
		String sql;
589
		Source destination =  pesiConfig.getDestination();
590

    
591
		// Clear RelTaxon
592
		sql = "DELETE FROM " + dbTableName;
593
		destination.setQuery(sql);
594
		destination.update(sql);
595
		return true;
596
	}
597

    
598
	@Override
599
	protected boolean isIgnore(PesiExportState state) {
600
		return ! state.getConfig().isDoRelTaxa();
601
	}
602

    
603
	/**
604
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
605
	 * @param relationship The {@link RelationshipBase Relationship}.
606
	 * @param state The {@link PesiExportState PesiExportState}.
607
	 * @return The <code>TaxonFk1</code> attribute.
608
	 * @see MethodMapper
609
	 */
610
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
611
		return getObjectFk(relationship, state, true);
612
	}
613

    
614
	/**
615
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
616
     * @param relationship The {@link RelationshipBase Relationship}.
617
     * @param state The {@link PesiExportState PesiExportState}.
618
     * @return The <code>TaxonFk1</code> attribute.
619
     * @see MethodMapper
620
     */
621
    private static Integer getTaxonFk1(Synonym synonym, PesiExportState state) {
622
        return synonym.getAcceptedTaxon().getId();
623
    }
624

    
625

    
626
	/**
627
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
628
	 * @param relationship The {@link RelationshipBase Relationship}.
629
	 * @param state The {@link PesiExportState PesiExportState}.
630
	 * @return The <code>TaxonFk2</code> attribute.
631
	 * @see MethodMapper
632
	 */
633
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
634
		return getObjectFk(relationship, state, false);
635
	}
636

    
637
	/**
638
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
639
	 * @param relationship The {@link RelationshipBase Relationship}.
640
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
641
	 * @see MethodMapper
642
	 */
643
	@SuppressWarnings("unused")
644
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
645
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
646
	}
647

    
648
	/**
649
	 * Returns the <code>RelQualifierCache</code> attribute.
650
	 * @param relationship The {@link RelationshipBase Relationship}.
651
	 * @return The <code>RelQualifierCache</code> attribute.
652
	 * @see MethodMapper
653
	 */
654
	@SuppressWarnings("unused")
655
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
656
		String result = null;
657
		NomenclaturalCode code = null;
658
		Taxon taxon = null;
659
		TaxonName name= null;
660
		if (relationship.isInstanceOf(TaxonRelationship.class)){
661
			TaxonRelationship rel = CdmBase.deproxy(relationship, TaxonRelationship.class);
662
			taxon = rel.getToTaxon();
663
			name = taxon.getName();
664
			code = name.getNomenclaturalCode();
665
			rel = null;
666

    
667
//		}else if (relationship.isInstanceOf(SynonymRelationship.class)){
668
//			SynonymRelationship rel = CdmBase.deproxy(relationship, SynonymRelationship.class);
669
//			taxon = rel.getAcceptedTaxon();
670
//			name = taxon.getName();
671
//			code = name.getNomenclaturalCode();
672
//			rel = null;
673

    
674
		}else if (relationship.isInstanceOf(NameRelationship.class)){
675
			NameRelationship rel = CdmBase.deproxy(relationship,  NameRelationship.class);
676
			name = rel.getFromName();
677
			code =name.getNomenclaturalCode();
678
			rel = null;
679

    
680
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
681
			HybridRelationship rel =  CdmBase.deproxy(relationship,  HybridRelationship.class);
682
			name = rel.getParentName();
683
			code = name.getNomenclaturalCode();
684
			rel = null;
685
		}
686
		taxon = null;
687
		name = null;
688
		if (code != null) {
689
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
690
		} else {
691
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
692
		}
693
		return result;
694
	}
695

    
696
	/**
697
	 * Returns the <code>Notes</code> attribute.
698
	 * @param relationship The {@link RelationshipBase Relationship}.
699
	 * @return The <code>Notes</code> attribute.
700
	 * @see MethodMapper
701
	 */
702
	@SuppressWarnings("unused")
703
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
704
		// TODO
705
		return null;
706
	}
707

    
708
	/**
709
	 * Returns the database key of an object in the given relationship.
710
	 * @param relationship {@link RelationshipBase RelationshipBase}.
711
	 * @param state {@link PesiExportState PesiExportState}.
712
	 * @param isFrom A boolean value indicating whether the database key of the parent or child in this relationship is searched. <code>true</code> means the child is searched. <code>false</code> means the parent is searched.
713
	 * @return The database key of an object in the given relationship.
714
	 */
715
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
716
		TaxonBase<?> taxonBase = null;
717
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
718
			TaxonRelationship tr = (TaxonRelationship)relationship;
719
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
720

    
721
//		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
722
//			SynonymRelationship sr = (SynonymRelationship)relationship;
723
//			taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
724
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
725
			if (isFrom){
726
				return state.getDbId(state.getCurrentFromObject());
727
			}else{
728
				return state.getDbId(state.getCurrentToObject());
729
			}
730
		}
731
		if (taxonBase != null) {
732
			if (! isPesiTaxon(taxonBase)){
733
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
734
				return null;
735
			}else{
736
				return state.getDbId(taxonBase);
737
			}
738

    
739
		}
740
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
741
		return null;
742
	}
743

    
744
	/**
745
	 * Returns the <code>RankFk</code> attribute.
746
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
747
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
748
	 * @return The <code>RankFk</code> attribute.
749
	 * @see MethodMapper
750
	 */
751
	private static Integer getRankFk(TaxonName taxonName, NomenclaturalCode nomenclaturalCode) {
752
		Integer result = null;
753
		if (nomenclaturalCode != null) {
754
			if (taxonName != null && taxonName.getRank() == null) {
755
				logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
756
			}
757
			result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
758
			if (result == null) {
759
				logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
760
			}
761
		}
762
		return result;
763
	}
764

    
765
	/**
766
	 * Returns the <code>RankCache</code> attribute.
767
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
768
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
769
	 * @param state
770
	 * @return The <code>RankCache</code> attribute.
771
	 * @see MethodMapper
772
	 */
773
	private static String getRankCache(TaxonName taxonName, NomenclaturalCode nomenclaturalCode, PesiExportState state) {
774
		if (nomenclaturalCode != null) {
775
			return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
776
		}else{
777
			logger.warn("No nomenclatural code defined for rank cache search");
778
			return null;
779
		}
780
	}
781

    
782
	/**
783
	 * Returns the CDM to PESI specific export mappings.
784
	 * @return The {@link PesiExportMapping PesiExportMapping}.
785
	 */
786
	PesiExportMapping getMapping() {
787
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
788

    
789
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
790
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
791
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
792
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
793
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
794

    
795
		return mapping;
796
	}
797

    
798
}
(9-9/12)