Project

General

Profile

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

    
12
import java.sql.Connection;
13
import java.sql.PreparedStatement;
14
import java.sql.SQLException;
15
import java.util.ArrayList;
16
import java.util.HashMap;
17
import java.util.List;
18
import java.util.Set;
19

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

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

    
42
/**
43
 * The export class for relations between {@link eu.etaxonomy.cdm.model.taxon.TaxonBase TaxonBases}.<p>
44
 * Inserts into DataWarehouse database table <code>RelTaxon</code>.
45
 * @author e.-m.lee
46
 * @date 23.02.2010
47
 *
48
 */
49
@Component
50
public class PesiRelTaxonExport extends PesiExportBase {
51
	private static final Logger logger = Logger.getLogger(PesiRelTaxonExport.class);
52
	private static final Class<? extends CdmBase> standardMethodParameter = RelationshipBase.class;
53

    
54
	private static int modCount = 1000;
55
	private static final String dbTableName = "RelTaxon";
56
	private static final String pluralString = "Relationships";
57
	private static PreparedStatement synonymsStmt;
58
	
59
	private HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();
60
	private List<Rank> rankList = new ArrayList<Rank>();
61
	private PesiExportMapping mapping;
62
	private int count = 0;
63
	
64
	public PesiRelTaxonExport() {
65
		super();
66
	}
67

    
68
	/* (non-Javadoc)
69
	 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
70
	 */
71
	@Override
72
	public Class<? extends CdmBase> getStandardMethodParameter() {
73
		return standardMethodParameter;
74
	}
75

    
76
	/* (non-Javadoc)
77
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
78
	 */
79
	@Override
80
	protected boolean doCheck(PesiExportState state) {
81
		boolean result = true;
82
		return result;
83
	}
84

    
85
	
86
	/* (non-Javadoc)
87
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
88
	 */
89
	@Override
90
	protected void doInvoke(PesiExportState state) {
91
		try {
92
			logger.info("*** Started Making " + pluralString + " ...");
93
	
94
			Connection connection = state.getConfig().getDestination().getConnection();
95
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?"; 
96
			synonymsStmt = connection.prepareStatement(synonymsSql);
97

    
98
			// Stores whether this invoke was successful or not.
99
			boolean success = true;
100

    
101
			// PESI: Clear the database table RelTaxon.
102
			doDelete(state);
103
	
104
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
105
			mapping = getMapping();
106

    
107
			// Initialize the db mapper
108
			mapping.initialize(state);
109
			
110
			//Export taxon relations
111
			success &= doPhase01(state, mapping);
112

    
113
			
114
			// Export name relations
115
			success &= doPhase02(state, mapping);
116

    
117
		} catch (SQLException e) {
118
			e.printStackTrace();
119
			logger.error(e.getMessage());
120
			state.setUnsuccessfull();
121
			return;
122
		}
123
	}
124
	
125
	
126
	private boolean doPhase01(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
127
		logger.info("PHASE 1: Taxon Relationships ...");
128
		boolean success = true;
129
		
130
		int limit = state.getConfig().getLimitSave();
131
		// Start transaction
132
		TransactionStatus txStatus = startTransaction(true);
133
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
134
		
135
		List<RelationshipBase> list;
136
		
137
		//taxon relations
138
		int partitionCount = 0;
139
		int totalCount = 0;
140
		while ((list = getNextTaxonRelationshipPartition( limit, partitionCount++, null)) != null ) {
141
			totalCount = totalCount + list.size();
142
			logger.info("Read " + list.size() + " PESI relations. Limit: " + limit + ". Total: " + totalCount );
143
//			if (list.size() > 0){
144
//				logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
145
//			}
146
			for (RelationshipBase rel : list){
147
				try {
148
					mapping.invoke(rel);
149
				} catch (Exception e) {
150
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
151
					e.printStackTrace();
152
				}
153
			}
154
		}
155
		list = null;
156
		
157
		return success;
158
	}
159
	
160
	private boolean doPhase02(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
161
		logger.info("PHASE 2: Name Relationships ...");
162
		boolean success = true;
163
		
164
		int limit = state.getConfig().getLimitSave();
165
		// Start transaction
166
		TransactionStatus txStatus = startTransaction(true);
167
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
168
		
169
		List<RelationshipBase> list;
170
		
171
		//name relations
172
		int partitionCount = 0;
173
		while ((list = getNextNameRelationshipPartition(null, limit, partitionCount++, null)) != null   ) {
174
			for (RelationshipBase rel : list){
175
				try {
176
					TaxonNameBase<?,?> name1;
177
					TaxonNameBase<?,?> name2;
178
					if (rel.isInstanceOf(HybridRelationship.class)){
179
						HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
180
						name1 = hybridRel.getParentName();
181
						name2 = hybridRel.getHybridName();
182
					}else if (rel.isInstanceOf(NameRelationship.class)){
183
						NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
184
						name1 = nameRel.getFromName();
185
						name2 = nameRel.getToName();
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
					
204
				} catch (Exception e) {
205
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
206
					e.printStackTrace();
207
				}
208
			}
209
		}
210
		list = null;
211
		logger.info("End PHASE 2: Name Relationships ...");
212
				
213
		return success;
214
	}
215

    
216
	private void makeList(TaxonNameBase<?, ?> name, List<IdentifiableEntity> list) {
217
		if (! hasPesiTaxon(name)){
218
			list.add(name);
219
		}else{
220
			for (TaxonBase taxon:  getPesiTaxa(name)){
221
				list.add(taxon);
222
			}
223
		}
224
	}
225

    
226
	/* (non-Javadoc)
227
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
228
	 */
229
	protected void doInvoke_Old(PesiExportState state) {
230
		try {
231
			logger.info("*** Started Making " + pluralString + " ...");
232
	
233
			Connection connection = state.getConfig().getDestination().getConnection();
234
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?"; 
235
			synonymsStmt = connection.prepareStatement(synonymsSql);
236

    
237
			// Stores whether this invoke was successful or not.
238
			boolean success = true;
239

    
240
			// PESI: Clear the database table RelTaxon.
241
			doDelete(state);
242
	
243
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
244
			mapping = getMapping();
245

    
246
			// Initialize the db mapper
247
			mapping.initialize(state);
248

    
249
			TransactionStatus txStatus = null;
250
			List<Classification> classificationList = null;
251
			
252
			// Specify starting ranks for tree traversing
253
			rankList.add(Rank.KINGDOM());
254
			rankList.add(Rank.GENUS());
255

    
256
			// Specify where to stop traversing (value) when starting at a specific Rank (key)
257
			rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
258
			rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
259
			
260
			// Retrieve list of classifications
261
			txStatus = startTransaction(true);
262
			logger.info("Started transaction. Fetching all classifications...");
263
			classificationList = getClassificationService().listClassifications(null, 0, null, null);
264
			commitTransaction(txStatus);
265
			logger.debug("Committed transaction.");
266

    
267
			logger.info("Fetched " + classificationList.size() + " classification(s).");
268

    
269
			for (Classification classification : classificationList) {
270
				for (Rank rank : rankList) {
271
					
272
					txStatus = startTransaction(true);
273
					logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
274

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

    
278
					commitTransaction(txStatus);
279
					logger.debug("Committed transaction.");
280

    
281
					for (TaxonNode rootNode : rankSpecificRootNodes) {
282
						txStatus = startTransaction(false);
283
						Rank endRank = rank2endRankMap.get(rank);
284
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till " + (endRank == null ? "leaves are reached ..." : "Rank " + endRank.getLabel() + " ..."));
285
						
286
						TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
287

    
288
						if (isPesiTaxon(newNode.getTaxon())){
289
							
290
							TaxonNode parentNode = newNode.getParent();
291
	
292
							success &=traverseTree(newNode, parentNode, endRank, state);
293
	
294
							commitTransaction(txStatus);
295
							logger.debug("Committed transaction.");
296
						}else{
297
							logger.debug("Taxon is not in PESI");
298
						}
299

    
300
					}
301
				}
302
			}
303

    
304
			logger.warn("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
305

    
306
			if (!success){
307
				state.setUnsuccessfull();
308
			}
309
			return;
310
		} catch (SQLException e) {
311
			e.printStackTrace();
312
			logger.error(e.getMessage());
313
			state.setUnsuccessfull();
314
			return;
315
		}
316
	}
317

    
318
	/**
319
	 * Traverses the classification recursively and stores determined values for every Taxon.
320
	 * @param childNode
321
	 * @param parentNode
322
	 * @param treeIndex
323
	 * @param fetchLevel
324
	 * @param state
325
	 */
326
	private boolean  traverseTree(TaxonNode childNode, TaxonNode parentNode, Rank fetchLevel, PesiExportState state) {
327
		boolean success = true;
328
		// Traverse all branches from this childNode until specified fetchLevel is reached.
329
		TaxonBase<?> childTaxon = childNode.getTaxon();
330
		if (childTaxon != null) {
331
			if (isPesiTaxon(childTaxon)){
332
				if (childTaxon.getName() != null) {
333
					Rank childTaxonNameRank = childTaxon.getName().getRank();
334
					if (childTaxonNameRank != null) {
335
						if (! childTaxonNameRank.equals(fetchLevel)) {
336
	
337
							success &= saveData(childNode, parentNode, state);
338
	
339
							for (TaxonNode newNode : childNode.getChildNodes()) {
340
								success &= traverseTree(newNode, childNode, fetchLevel, state);
341
							}
342
							
343
						} else {
344
	//						logger.error("Target Rank " + fetchLevel.getLabel() + " reached");
345
							return success;
346
						}
347
					} else {
348
						logger.warn("Rank is NULL. FetchLevel can not be checked: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
349
					}
350
				} else {
351
					logger.error("TaxonName is NULL for taxon: " + childTaxon.getUuid());
352
				}
353
			}else{
354
				logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
355
			}
356

    
357
		} else {
358
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
359
		}
360
		return success;
361
	}
362

    
363
	/**
364
	 * Stores values in database for every recursive round.
365
	 * @param childNode
366
	 * @param parentNode
367
	 * @param treeIndex
368
	 * @param state
369
	 * @param currentTaxonFk
370
	 */
371
	private boolean saveData(TaxonNode childNode, TaxonNode parentNode, PesiExportState state) {
372
		boolean success = true;
373
		Taxon childNodeTaxon = childNode.getTaxon();
374
		if (childNodeTaxon != null) {
375
			// TaxonRelationships
376
			success &= saveTaxonRelationships(state, childNodeTaxon);
377
			// TaxonNameRelationships
378
			success &= saveNameRelationships(state, childNodeTaxon);
379
			// SynonymRelationships
380
			success &= saveSynonymAndSynNameRelationships(state, childNodeTaxon);
381
		}
382
		return success;
383
		
384
	}
385

    
386
	private boolean saveSynonymAndSynNameRelationships(PesiExportState state, Taxon childNodeTaxon) {
387
		boolean success = true;
388
		for (SynonymRelationship synRel : childNodeTaxon.getSynonymRelations()) { // synonyms of accepted taxon
389
			Synonym synonym = synRel.getSynonym();
390
			TaxonNameBase<?,?> synonymTaxonName = synonym.getName();
391
			if (! isPesiTaxon(synonym)){
392
				logger.warn("Synonym " + synonym.getId() + " of synonym relation " + synRel.getId() + " is not a PESI taxon. Can't export relationship");
393
				continue;
394
			}
395
			
396
			// Store synonym data in Taxon table
397
			invokeSynonyms(state, synonymTaxonName);
398

    
399
			
400
			
401
			Set<SynonymRelationship> synonymRelations = synonym.getSynonymRelations();
402
			state.setCurrentFromObject(synonym);
403
			for (SynonymRelationship synonymRelationship : synonymRelations) {  //needed? Maybe to make sure that there are no partial synonym relations missed ??
404
				try {
405
					if (neededValuesNotNull(synonymRelationship, state)) {
406
						doCount(count++, modCount, pluralString);
407
						success &= mapping.invoke(synonymRelationship);
408
						
409
					}
410
				} catch (SQLException e) {
411
					logger.error("SynonymRelationship (" + synonymRelationship.getUuid() + ") could not be stored : " + e.getMessage());
412
				}
413
			}
414

    
415
			// SynonymNameRelationship
416
			success &= saveNameRelationships(state, synonym);
417
		}
418
		return success;
419
	}
420

    
421
	private boolean saveNameRelationships(PesiExportState state, TaxonBase taxonBase) {
422
		boolean success = true;
423
		TaxonNameBase<?,?> childNodeTaxonName = taxonBase.getName();
424

    
425
		//from relations
426
		Set<NameRelationship> nameRelations = childNodeTaxonName.getRelationsFromThisName();
427
		state.setCurrentFromObject(taxonBase);
428
		boolean isFrom = true;
429
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
430
		
431
		//toRelations
432
		nameRelations = childNodeTaxonName.getRelationsToThisName();
433
		state.setCurrentToObject(taxonBase);
434
		isFrom = false;
435
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
436
		
437
		return success;
438
	}
439

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

    
460
	private boolean checkAndInvokeNameRelation(PesiExportState state, NameRelationship nameRelation, IdentifiableEntity<?> relatedObject, boolean isFrom) throws SQLException {
461
		boolean success = true;
462
		if (isFrom){
463
			state.setCurrentToObject(relatedObject);
464
		}else{
465
			state.setCurrentFromObject(relatedObject);
466
		}
467
		if (neededValuesNotNull(nameRelation, state)) {
468
			doCount(count++, modCount, pluralString);
469
			success &= mapping.invoke(nameRelation);
470
		}
471
		return success;
472
	}
473

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

    
491
	/**
492
	 * Determines synonym related data and saves them.
493
	 * @param state
494
	 * @param sr
495
	 */
496
	private static void invokeSynonyms(PesiExportState state, TaxonNameBase synonymTaxonName) {
497
		// Store KingdomFk and Rank information in Taxon table
498
		Integer kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(synonymTaxonName.getNomenclaturalCode());
499
		Integer synonymFk = state.getDbId(synonymTaxonName);
500

    
501
		saveSynonymData(synonymTaxonName, synonymTaxonName.getNomenclaturalCode(), kingdomFk, synonymFk);
502
	}
503

    
504
	/**
505
	 * Stores synonym data.
506
	 * @param taxonName
507
	 * @param nomenclaturalCode
508
	 * @param kingdomFk
509
	 * @param synonymParentTaxonFk
510
	 * @param currentTaxonFk
511
	 */
512
	private static boolean saveSynonymData(TaxonNameBase taxonName,
513
			NomenclaturalCode nomenclaturalCode, Integer kingdomFk,
514
			Integer currentSynonymFk) {
515
		try {
516
			if (kingdomFk != null) {
517
				synonymsStmt.setInt(1, kingdomFk);
518
			} else {
519
				synonymsStmt.setObject(1, null);
520
			}
521
			
522
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
523
			if (rankFk != null) {
524
				synonymsStmt.setInt(2, rankFk);
525
			} else {
526
				synonymsStmt.setObject(2, null);
527
			}
528
			synonymsStmt.setString(3, getRankCache(taxonName, nomenclaturalCode));
529
			
530
			if (currentSynonymFk != null) {
531
				synonymsStmt.setInt(4, currentSynonymFk);
532
			} else {
533
				synonymsStmt.setObject(4, null);
534
			}
535
			synonymsStmt.executeUpdate();
536
			return true;
537
		} catch (SQLException e) {
538
			logger.error("SQLException during invoke for taxonName - " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + "): " + e.getMessage());
539
			e.printStackTrace();
540
			return false;
541
		}
542
	}
543

    
544
	/**
545
	 * Checks whether needed values for an entity are NULL.
546
	 * @return
547
	 */
548
	private boolean neededValuesNotNull(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
549
		boolean result = true;
550
		if (getTaxonFk1(relationship, state) == null) {
551
			logger.warn("TaxonFk1 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
552
			result = false;
553
		}
554
		if (getTaxonFk2(relationship, state) == null) {
555
			logger.warn("TaxonFk2 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
556
			result = false;
557
		}
558
		return result;
559
	}
560
	
561
	/**
562
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
563
	 * @param state The {@link PesiExportState PesiExportState}.
564
	 * @return Whether the delete operation was successful or not.
565
	 */
566
	protected boolean doDelete(PesiExportState state) {
567
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
568
		
569
		String sql;
570
		Source destination =  pesiConfig.getDestination();
571

    
572
		// Clear RelTaxon
573
		sql = "DELETE FROM " + dbTableName;
574
		destination.setQuery(sql);
575
		destination.update(sql);
576
		return true;
577
	}
578

    
579
	/* (non-Javadoc)
580
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
581
	 */
582
	@Override
583
	protected boolean isIgnore(PesiExportState state) {
584
		return ! state.getConfig().isDoRelTaxa();
585
	}
586

    
587
	/**
588
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
589
	 * @param relationship The {@link RelationshipBase Relationship}.
590
	 * @param state The {@link PesiExportState PesiExportState}.
591
	 * @return The <code>TaxonFk1</code> attribute.
592
	 * @see MethodMapper
593
	 */
594
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
595
		return getObjectFk(relationship, state, true);
596
	}
597
	
598
	/**
599
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
600
	 * @param relationship The {@link RelationshipBase Relationship}.
601
	 * @param state The {@link PesiExportState PesiExportState}.
602
	 * @return The <code>TaxonFk2</code> attribute.
603
	 * @see MethodMapper
604
	 */
605
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
606
		return getObjectFk(relationship, state, false);
607
	}
608
	
609
	/**
610
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
611
	 * @param relationship The {@link RelationshipBase Relationship}.
612
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
613
	 * @see MethodMapper
614
	 */
615
	@SuppressWarnings("unused")
616
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
617
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
618
	}
619
	
620
	/**
621
	 * Returns the <code>RelQualifierCache</code> attribute.
622
	 * @param relationship The {@link RelationshipBase Relationship}.
623
	 * @return The <code>RelQualifierCache</code> attribute.
624
	 * @see MethodMapper
625
	 */
626
	@SuppressWarnings("unused")
627
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
628
		String result = null;
629
		NomenclaturalCode code = null;
630
		if (relationship.isInstanceOf(TaxonRelationship.class)){
631
			code = CdmBase.deproxy(relationship, TaxonRelationship.class).getToTaxon().getName().getNomenclaturalCode();
632
		}else if (relationship.isInstanceOf(SynonymRelationship.class)){
633
			code = CdmBase.deproxy(relationship, SynonymRelationship.class).getAcceptedTaxon().getName().getNomenclaturalCode();
634
		}else if (relationship.isInstanceOf(NameRelationship.class)){
635
			code = CdmBase.deproxy(relationship,  NameRelationship.class).getFromName().getNomenclaturalCode();
636
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
637
			code = CdmBase.deproxy(relationship,  HybridRelationship.class).getParentName().getNomenclaturalCode();
638
		}
639
		if (code != null) {
640
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
641
		} else {
642
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
643
		}
644
		return result;
645
	}
646
	
647
	/**
648
	 * Returns the <code>Notes</code> attribute.
649
	 * @param relationship The {@link RelationshipBase Relationship}.
650
	 * @return The <code>Notes</code> attribute.
651
	 * @see MethodMapper
652
	 */
653
	@SuppressWarnings("unused")
654
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
655
		// TODO
656
		return null;
657
	}
658

    
659
	/**
660
	 * Returns the database key of an object in the given relationship.
661
	 * @param relationship {@link RelationshipBase RelationshipBase}.
662
	 * @param state {@link PesiExportState PesiExportState}.
663
	 * @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.
664
	 * @return The database key of an object in the given relationship.
665
	 */
666
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
667
		TaxonBase<?> taxonBase = null;
668
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
669
			TaxonRelationship tr = (TaxonRelationship)relationship;
670
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
671
		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
672
			SynonymRelationship sr = (SynonymRelationship)relationship;
673
			taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
674
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
675
			if (isFrom){
676
				return state.getDbId(state.getCurrentFromObject());
677
			}else{
678
				return state.getDbId(state.getCurrentToObject());
679
			}
680
		}
681
		if (taxonBase != null) {
682
			if (! isPesiTaxon(taxonBase)){
683
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
684
				return null;
685
			}else{
686
				return state.getDbId(taxonBase);	
687
			}
688
			
689
		}
690
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
691
		return null;
692
	}
693

    
694
	/**
695
	 * Returns the <code>RankFk</code> attribute.
696
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
697
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
698
	 * @return The <code>RankFk</code> attribute.
699
	 * @see MethodMapper
700
	 */
701
	private static Integer getRankFk(TaxonNameBase taxonName, NomenclaturalCode nomenclaturalCode) {
702
		Integer result = null;
703
		if (nomenclaturalCode != null) {
704
			if (taxonName != null && taxonName.getRank() == null) {
705
				logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
706
			}
707
			result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
708
			if (result == null) {
709
				logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
710
			}
711
		}
712
		return result;
713
	}
714

    
715
	/**
716
	 * Returns the <code>RankCache</code> attribute.
717
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
718
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
719
	 * @return The <code>RankCache</code> attribute.
720
	 * @see MethodMapper
721
	 */
722
	private static String getRankCache(TaxonNameBase taxonName, NomenclaturalCode nomenclaturalCode) {
723
		String result = null;
724
		if (nomenclaturalCode != null) {
725
			result = PesiTransformer.rank2RankCache(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
726
		}
727
		return result;
728
	}
729

    
730
	/**
731
	 * Returns the CDM to PESI specific export mappings.
732
	 * @return The {@link PesiExportMapping PesiExportMapping}.
733
	 */
734
	PesiExportMapping getMapping() {
735
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
736
		
737
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
738
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
739
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
740
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
741
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
742

    
743
		return mapping;
744
	}
745

    
746
}
(14-14/17)