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
 * @since 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
	protected void doInvoke_Old(PesiExportState state) {
237
		try {
238
			logger.info("*** Started Making " + pluralString + " ...");
239

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

    
244
			// Stores whether this invoke was successful or not.
245
			boolean success = true;
246

    
247
			// PESI: Clear the database table RelTaxon.
248
			doDelete(state);
249

    
250
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
251
			mapping = getMapping();
252

    
253
			// Initialize the db mapper
254
			mapping.initialize(state);
255

    
256
			TransactionStatus txStatus = null;
257
			List<Classification> classificationList = null;
258

    
259
			// Specify starting ranks for tree traversing
260
			rankList.add(Rank.KINGDOM());
261
			rankList.add(Rank.GENUS());
262

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

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

    
274
			logger.info("Fetched " + classificationList.size() + " classification(s).");
275

    
276
			boolean includeUnpublished = false;
277
			for (Classification classification : classificationList) {
278
				for (Rank rank : rankList) {
279

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

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

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

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

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

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

    
299
							TaxonNode parentNode = newNode.getParent();
300

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

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

    
309
					}
310
				}
311
			}
312

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

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

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

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

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

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

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

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

    
393
	}
394

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

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

    
407

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

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

    
418

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

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

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

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

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

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

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

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

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

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

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

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

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

    
561

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

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

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

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

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

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

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

    
624

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

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

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

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

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

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

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

    
707
	/**
708
	 * Returns the database key of an object in the given relationship.
709
	 * @param relationship {@link RelationshipBase RelationshipBase}.
710
	 * @param state {@link PesiExportState PesiExportState}.
711
	 * @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.
712
	 * @return The database key of an object in the given relationship.
713
	 */
714
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
715
		TaxonBase<?> taxonBase = null;
716
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
717
			TaxonRelationship tr = (TaxonRelationship)relationship;
718
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
719

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

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

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

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

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

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

    
794
		return mapping;
795
	}
796

    
797
}
(9-9/12)