Project

General

Profile

Download (27.4 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.Taxon;
37
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
38
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
39
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
40

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

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

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

    
63
	public PesiRelTaxonExport() {
64
		super();
65
	}
66

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

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

    
84

    
85
	/* (non-Javadoc)
86
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
87
	 */
88
	@Override
89
	protected void doInvoke(PesiExportState state) {
90
		try {
91
			logger.info("*** Started Making " + pluralString + " ...");
92

    
93
			Connection connection = state.getConfig().getDestination().getConnection();
94
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?";
95
			synonymsStmt = connection.prepareStatement(synonymsSql);
96

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

    
100
			// PESI: Clear the database table RelTaxon.
101
			//doDelete(state); -> done by stored procedure
102

    
103
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
104
			mapping = getMapping();
105

    
106
			// Initialize the db mapper
107
			mapping.initialize(state);
108

    
109
			//Export taxon relations
110
			success &= doPhase01(state, mapping);
111

    
112

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

    
116
			if (! success){
117
				state.setUnsuccessfull();
118
			}
119

    
120
		} catch (SQLException e) {
121
			e.printStackTrace();
122
			logger.error(e.getMessage());
123
			state.setUnsuccessfull();
124
			return;
125
		}
126
	}
127

    
128

    
129
	private boolean doPhase01(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
130
		logger.info("PHASE 1: Taxon Relationships ...");
131
		boolean success = true;
132

    
133
		int limit = state.getConfig().getLimitSave();
134
		// Start transaction
135
		TransactionStatus txStatus = startTransaction(true);
136
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
137

    
138
		List<RelationshipBase> list;
139

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

    
158
			commitTransaction(txStatus);
159
			txStatus = startTransaction();
160
		}
161
		list = null;
162
		commitTransaction(txStatus);
163
		return success;
164
	}
165

    
166
	private boolean doPhase02(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
167
		logger.info("PHASE 2: Name Relationships ...");
168
		boolean success = true;
169

    
170
		int limit = state.getConfig().getLimitSave();
171
		// Start transaction
172
		TransactionStatus txStatus = startTransaction(true);
173
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
174

    
175
		List<RelationshipBase> list;
176

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

    
203
					for (IdentifiableEntity fromEntity : fromList){
204
						for (IdentifiableEntity toEntity : toList){
205
							//TODO set entities to state
206
							state.setCurrentFromObject(fromEntity);
207
							state.setCurrentToObject(toEntity);
208
							mapping.invoke(rel);
209
						}
210
					}
211
					fromList = null;
212
					toList = null;
213
					name1 = null;
214
					name2 = null;
215
					rel = null;
216

    
217

    
218
				} catch (Exception e) {
219
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
220
					e.printStackTrace();
221
				}
222
			}
223
			commitTransaction(txStatus);
224
			txStatus = startTransaction();
225
		}
226
		commitTransaction(txStatus);
227
		list = null;
228
		logger.info("End PHASE 2: Name Relationships ...");
229
		state.setCurrentFromObject(null);
230
		state.setCurrentToObject(null);
231
		return success;
232
	}
233

    
234
	private void makeList(TaxonNameBase<?, ?> name, List<IdentifiableEntity> list) {
235
		if (! hasPesiTaxon(name)){
236
			list.add(name);
237
		}else{
238
			for (TaxonBase taxon:  getPesiTaxa(name)){
239
				list.add(taxon);
240
			}
241
		}
242
	}
243

    
244
	/* (non-Javadoc)
245
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
246
	 */
247
	protected void doInvoke_Old(PesiExportState state) {
248
		try {
249
			logger.info("*** Started Making " + pluralString + " ...");
250

    
251
			Connection connection = state.getConfig().getDestination().getConnection();
252
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?";
253
			synonymsStmt = connection.prepareStatement(synonymsSql);
254

    
255
			// Stores whether this invoke was successful or not.
256
			boolean success = true;
257

    
258
			// PESI: Clear the database table RelTaxon.
259
			doDelete(state);
260

    
261
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
262
			mapping = getMapping();
263

    
264
			// Initialize the db mapper
265
			mapping.initialize(state);
266

    
267
			TransactionStatus txStatus = null;
268
			List<Classification> classificationList = null;
269

    
270
			// Specify starting ranks for tree traversing
271
			rankList.add(Rank.KINGDOM());
272
			rankList.add(Rank.GENUS());
273

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

    
278
			// Retrieve list of classifications
279
			txStatus = startTransaction(true);
280
			logger.info("Started transaction. Fetching all classifications...");
281
			classificationList = getClassificationService().listClassifications(null, 0, null, null);
282
			commitTransaction(txStatus);
283
			logger.debug("Committed transaction.");
284

    
285
			logger.info("Fetched " + classificationList.size() + " classification(s).");
286

    
287
			for (Classification classification : classificationList) {
288
				for (Rank rank : rankList) {
289

    
290
					txStatus = startTransaction(true);
291
					logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
292

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

    
296
					commitTransaction(txStatus);
297
					logger.debug("Committed transaction.");
298

    
299
					for (TaxonNode rootNode : rankSpecificRootNodes) {
300
						txStatus = startTransaction(false);
301
						Rank endRank = rank2endRankMap.get(rank);
302
						logger.debug("Started transaction to traverse childNodes of rootNode (" + rootNode.getUuid() + ") till " + (endRank == null ? "leaves are reached ..." : "Rank " + endRank.getLabel() + " ..."));
303

    
304
						TaxonNode newNode = getTaxonNodeService().load(rootNode.getUuid());
305

    
306
						if (isPesiTaxon(newNode.getTaxon())){
307

    
308
							TaxonNode parentNode = newNode.getParent();
309

    
310
							success &=traverseTree(newNode, parentNode, endRank, state);
311

    
312
							commitTransaction(txStatus);
313
							logger.debug("Committed transaction.");
314
						}else{
315
							logger.debug("Taxon is not in PESI");
316
						}
317

    
318
					}
319
				}
320
			}
321

    
322
			logger.warn("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
323

    
324
			if (!success){
325
				state.setUnsuccessfull();
326
			}
327
			return;
328
		} catch (SQLException e) {
329
			e.printStackTrace();
330
			logger.error(e.getMessage());
331
			state.setUnsuccessfull();
332
			return;
333
		}
334
	}
335

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

    
355
							success &= saveData(childNode, parentNode, state);
356

    
357
							for (TaxonNode newNode : childNode.getChildNodes()) {
358
								success &= traverseTree(newNode, childNode, fetchLevel, state);
359
							}
360

    
361
						} else {
362
	//						logger.error("Target Rank " + fetchLevel.getLabel() + " reached");
363
							return success;
364
						}
365
					} else {
366
						logger.warn("Rank is NULL. FetchLevel can not be checked: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
367
					}
368
				} else {
369
					logger.error("TaxonName is NULL for taxon: " + childTaxon.getUuid());
370
				}
371
			}else{
372
				logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
373
			}
374

    
375
		} else {
376
			logger.error("Taxon is NULL for TaxonNode: " + childNode.getUuid());
377
		}
378
		return success;
379
	}
380

    
381
	/**
382
	 * Stores values in database for every recursive round.
383
	 * @param childNode
384
	 * @param parentNode
385
	 * @param treeIndex
386
	 * @param state
387
	 * @param currentTaxonFk
388
	 */
389
	private boolean saveData(TaxonNode childNode, TaxonNode parentNode, PesiExportState state) {
390
		boolean success = true;
391
		Taxon childNodeTaxon = childNode.getTaxon();
392
		if (childNodeTaxon != null) {
393
			// TaxonRelationships
394
			success &= saveTaxonRelationships(state, childNodeTaxon);
395
			// TaxonNameRelationships
396
			success &= saveNameRelationships(state, childNodeTaxon);
397
			// SynonymRelationships
398
			success &= saveSynonymAndSynNameRelationships(state, childNodeTaxon);
399
		}
400
		return success;
401

    
402
	}
403

    
404
	private boolean saveSynonymAndSynNameRelationships(PesiExportState state, Taxon childNodeTaxon) {
405
		boolean success = true;
406
		for (Synonym synonym : childNodeTaxon.getSynonyms()) { // synonyms of accepted taxon
407
			TaxonNameBase<?,?> synonymTaxonName = synonym.getName();
408
			if (! isPesiTaxon(synonym)){
409
				logger.warn("Synonym " + synonym.getId() + " is not a PESI taxon. Can't export relationship");
410
				continue;
411
			}
412

    
413
			// Store synonym data in Taxon table
414
			invokeSynonyms(state, synonymTaxonName);
415

    
416

    
417
			try {
418
				if (neededValuesNotNull(synonym, state)) {
419
					doCount(count++, modCount, pluralString);
420
					success &= mapping.invoke(synonym);
421

    
422
				}
423
			} catch (SQLException e) {
424
				logger.error("Synonym (" + synonym.getUuid() + ") could not be stored : " + e.getMessage());
425
			}
426

    
427

    
428
			// SynonymNameRelationship
429
			success &= saveNameRelationships(state, synonym);
430
		}
431
		state.setCurrentFromObject(null);
432
		return success;
433
	}
434

    
435
	private boolean saveNameRelationships(PesiExportState state, TaxonBase taxonBase) {
436
		boolean success = true;
437
		TaxonNameBase<?,?> childNodeTaxonName = taxonBase.getName();
438

    
439
		//from relations
440
		Set<NameRelationship> nameRelations = childNodeTaxonName.getRelationsFromThisName();
441
		state.setCurrentFromObject(taxonBase);
442
		boolean isFrom = true;
443
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
444

    
445
		//toRelations
446
		nameRelations = childNodeTaxonName.getRelationsToThisName();
447
		state.setCurrentToObject(taxonBase);
448
		isFrom = false;
449
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
450
		state.setCurrentToObject(null);
451
		return success;
452
	}
453

    
454
	private boolean saveOneSideNameRelation(PesiExportState state, boolean isFrom, Set<NameRelationship> nameRelations) {
455
		boolean success = true;
456
		for (NameRelationship nameRelation : nameRelations) {
457
			try {
458
				TaxonNameBase<?,?> relatedName = isFrom ? nameRelation.getToName(): nameRelation.getFromName();
459
				if ( isPurePesiName(relatedName)){
460
					success &= checkAndInvokeNameRelation(state, nameRelation, relatedName, isFrom);
461
				}else{
462
					for (TaxonBase<?> relatedTaxon : getPesiTaxa(relatedName)){
463
						success &= checkAndInvokeNameRelation(state, nameRelation, relatedTaxon, isFrom);
464
					}
465
				}
466
			} catch (SQLException e) {
467
				logger.error("NameRelationship " + nameRelation.getUuid() + " for " + nameRelation.getFromName().getTitleCache() + " and " + nameRelation.getToName().getTitleCache() + " could not be created: " + e.getMessage());
468
				success = false;
469
			}
470
		}
471
		return success;
472
	}
473

    
474
	private boolean checkAndInvokeNameRelation(PesiExportState state, NameRelationship nameRelation, IdentifiableEntity<?> relatedObject, boolean isFrom) throws SQLException {
475
		boolean success = true;
476
		if (isFrom){
477
			state.setCurrentToObject(relatedObject);
478
		}else{
479
			state.setCurrentFromObject(relatedObject);
480
		}
481
		if (neededValuesNotNull(nameRelation, state)) {
482
			doCount(count++, modCount, pluralString);
483
			success &= mapping.invoke(nameRelation);
484
		}
485
		state.setCurrentFromObject(null);
486
		state.setCurrentToObject(null);
487
		return success;
488
	}
489

    
490
	private boolean saveTaxonRelationships(PesiExportState state, Taxon childNodeTaxon) {
491
		boolean success = true;
492
		Taxon taxon = childNodeTaxon;
493
		Set<TaxonRelationship> taxonRelations = taxon.getRelationsToThisTaxon();
494
		for (TaxonRelationship taxonRelationship : taxonRelations) {
495
			try {
496
				if (neededValuesNotNull(taxonRelationship, state)) {
497
					doCount(count++, modCount, pluralString);
498
					success &= mapping.invoke(taxonRelationship);
499
				}
500
			} catch (SQLException e) {
501
				logger.error("TaxonRelationship could not be created for this TaxonRelation (" + taxonRelationship.getUuid() + "): " + e.getMessage());
502
			}
503
		}
504
		return success;
505
	}
506

    
507
	/**
508
	 * Determines synonym related data and saves them.
509
	 * @param state
510
	 * @param sr
511
	 */
512
	private void invokeSynonyms(PesiExportState state, TaxonNameBase synonymTaxonName) {
513
		// Store KingdomFk and Rank information in Taxon table
514
		Integer kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(synonymTaxonName.getNomenclaturalCode());
515
		Integer synonymFk = state.getDbId(synonymTaxonName);
516

    
517
		saveSynonymData(state, synonymTaxonName, synonymTaxonName.getNomenclaturalCode(), kingdomFk, synonymFk);
518
	}
519

    
520
	/**
521
	 * Stores synonym data.
522
	 * @param state
523
	 * @param taxonName
524
	 * @param nomenclaturalCode
525
	 * @param kingdomFk
526
	 * @param synonymParentTaxonFk
527
	 * @param currentTaxonFk
528
	 */
529
	private boolean saveSynonymData(PesiExportState state, TaxonNameBase taxonName,
530
			NomenclaturalCode nomenclaturalCode, Integer kingdomFk,
531
			Integer currentSynonymFk) {
532
		try {
533
			if (kingdomFk != null) {
534
				synonymsStmt.setInt(1, kingdomFk);
535
			} else {
536
				synonymsStmt.setObject(1, null);
537
			}
538

    
539
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
540
			if (rankFk != null) {
541
				synonymsStmt.setInt(2, rankFk);
542
			} else {
543
				synonymsStmt.setObject(2, null);
544
			}
545
			synonymsStmt.setString(3, getRankCache(taxonName, nomenclaturalCode, state));
546

    
547
			if (currentSynonymFk != null) {
548
				synonymsStmt.setInt(4, currentSynonymFk);
549
			} else {
550
				synonymsStmt.setObject(4, null);
551
			}
552
			synonymsStmt.executeUpdate();
553
			return true;
554
		} catch (SQLException e) {
555
			logger.error("SQLException during invoke for taxonName - " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + "): " + e.getMessage());
556
			e.printStackTrace();
557
			return false;
558
		}
559
	}
560

    
561
	private boolean neededValuesNotNull(Synonym synonym, PesiExportState state) {
562
	    boolean result = true;
563
        if (getTaxonFk1(synonym, state) == null) {
564
            logger.warn("TaxonFk1 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
565
            result = false;
566
        }
567
        return result;
568
	}
569

    
570

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

    
588
	/**
589
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
590
	 * @param state The {@link PesiExportState PesiExportState}.
591
	 * @return Whether the delete operation was successful or not.
592
	 */
593
	protected boolean doDelete(PesiExportState state) {
594
		PesiExportConfigurator pesiConfig = state.getConfig();
595

    
596
		String sql;
597
		Source destination =  pesiConfig.getDestination();
598

    
599
		// Clear RelTaxon
600
		sql = "DELETE FROM " + dbTableName;
601
		destination.setQuery(sql);
602
		destination.update(sql);
603
		return true;
604
	}
605

    
606
	/* (non-Javadoc)
607
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
608
	 */
609
	@Override
610
	protected boolean isIgnore(PesiExportState state) {
611
		return ! state.getConfig().isDoRelTaxa();
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(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
622
		return getObjectFk(relationship, state, true);
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
		TaxonNameBase 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
		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
720
			SynonymRelationship sr = (SynonymRelationship)relationship;
721
			taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
722
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
723
			if (isFrom){
724
				return state.getDbId(state.getCurrentFromObject());
725
			}else{
726
				return state.getDbId(state.getCurrentToObject());
727
			}
728
		}
729
		if (taxonBase != null) {
730
			if (! isPesiTaxon(taxonBase)){
731
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
732
				return null;
733
			}else{
734
				return state.getDbId(taxonBase);
735
			}
736

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

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

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

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

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

    
793
		return mapping;
794
	}
795

    
796
}
(9-9/12)