Project

General

Profile

Download (27.9 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.TaxonNameBase;
33
import eu.etaxonomy.cdm.model.taxon.Classification;
34
import eu.etaxonomy.cdm.model.taxon.Synonym;
35
import eu.etaxonomy.cdm.model.taxon.Taxon;
36
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
37
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
38
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
39

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

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

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

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

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

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

    
83

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

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

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

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

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

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

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

    
111

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

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

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

    
127

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

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

    
137
		List<RelationshipBase> list;
138

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

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

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

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

    
174
		List<RelationshipBase> list;
175

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

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

    
216

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
307
							TaxonNode parentNode = newNode.getParent();
308

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

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

    
317
					}
318
				}
319
			}
320

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

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

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

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

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

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

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

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

    
401
	}
402

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

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

    
415

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

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

    
426

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

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

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

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

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

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

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

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

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

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

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

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

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

    
569

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

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

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

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

    
605
	/* (non-Javadoc)
606
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
607
	 */
608
	@Override
609
	protected boolean isIgnore(PesiExportState state) {
610
		return ! state.getConfig().isDoRelTaxa();
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(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
621
		return getObjectFk(relationship, state, true);
622
	}
623

    
624
	/**
625
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
626
     * @param relationship The {@link RelationshipBase Relationship}.
627
     * @param state The {@link PesiExportState PesiExportState}.
628
     * @return The <code>TaxonFk1</code> attribute.
629
     * @see MethodMapper
630
     */
631
    private static Integer getTaxonFk1(Synonym synonym, PesiExportState state) {
632
        return synonym.getAcceptedTaxon().getId();
633
    }
634

    
635

    
636
	/**
637
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
638
	 * @param relationship The {@link RelationshipBase Relationship}.
639
	 * @param state The {@link PesiExportState PesiExportState}.
640
	 * @return The <code>TaxonFk2</code> attribute.
641
	 * @see MethodMapper
642
	 */
643
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
644
		return getObjectFk(relationship, state, false);
645
	}
646

    
647
	/**
648
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
649
	 * @param relationship The {@link RelationshipBase Relationship}.
650
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
651
	 * @see MethodMapper
652
	 */
653
	@SuppressWarnings("unused")
654
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
655
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
656
	}
657

    
658
	/**
659
	 * Returns the <code>RelQualifierCache</code> attribute.
660
	 * @param relationship The {@link RelationshipBase Relationship}.
661
	 * @return The <code>RelQualifierCache</code> attribute.
662
	 * @see MethodMapper
663
	 */
664
	@SuppressWarnings("unused")
665
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
666
		String result = null;
667
		NomenclaturalCode code = null;
668
		Taxon taxon = null;
669
		TaxonNameBase name= null;
670
		if (relationship.isInstanceOf(TaxonRelationship.class)){
671
			TaxonRelationship rel = CdmBase.deproxy(relationship, TaxonRelationship.class);
672
			taxon = rel.getToTaxon();
673
			name = taxon.getName();
674
			code = name.getNomenclaturalCode();
675
			rel = null;
676

    
677
//		}else if (relationship.isInstanceOf(SynonymRelationship.class)){
678
//			SynonymRelationship rel = CdmBase.deproxy(relationship, SynonymRelationship.class);
679
//			taxon = rel.getAcceptedTaxon();
680
//			name = taxon.getName();
681
//			code = name.getNomenclaturalCode();
682
//			rel = null;
683

    
684
		}else if (relationship.isInstanceOf(NameRelationship.class)){
685
			NameRelationship rel = CdmBase.deproxy(relationship,  NameRelationship.class);
686
			name = rel.getFromName();
687
			code =name.getNomenclaturalCode();
688
			rel = null;
689

    
690
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
691
			HybridRelationship rel =  CdmBase.deproxy(relationship,  HybridRelationship.class);
692
			name = rel.getParentName();
693
			code = name.getNomenclaturalCode();
694
			rel = null;
695
		}
696
		taxon = null;
697
		name = null;
698
		if (code != null) {
699
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
700
		} else {
701
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
702
		}
703
		return result;
704
	}
705

    
706
	/**
707
	 * Returns the <code>Notes</code> attribute.
708
	 * @param relationship The {@link RelationshipBase Relationship}.
709
	 * @return The <code>Notes</code> attribute.
710
	 * @see MethodMapper
711
	 */
712
	@SuppressWarnings("unused")
713
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
714
		// TODO
715
		return null;
716
	}
717

    
718
	/**
719
	 * Returns the database key of an object in the given relationship.
720
	 * @param relationship {@link RelationshipBase RelationshipBase}.
721
	 * @param state {@link PesiExportState PesiExportState}.
722
	 * @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.
723
	 * @return The database key of an object in the given relationship.
724
	 */
725
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
726
		TaxonBase<?> taxonBase = null;
727
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
728
			TaxonRelationship tr = (TaxonRelationship)relationship;
729
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
730

    
731
//		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
732
//			SynonymRelationship sr = (SynonymRelationship)relationship;
733
//			taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
734
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
735
			if (isFrom){
736
				return state.getDbId(state.getCurrentFromObject());
737
			}else{
738
				return state.getDbId(state.getCurrentToObject());
739
			}
740
		}
741
		if (taxonBase != null) {
742
			if (! isPesiTaxon(taxonBase)){
743
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
744
				return null;
745
			}else{
746
				return state.getDbId(taxonBase);
747
			}
748

    
749
		}
750
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
751
		return null;
752
	}
753

    
754
	/**
755
	 * Returns the <code>RankFk</code> attribute.
756
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
757
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
758
	 * @return The <code>RankFk</code> attribute.
759
	 * @see MethodMapper
760
	 */
761
	private static Integer getRankFk(TaxonNameBase taxonName, NomenclaturalCode nomenclaturalCode) {
762
		Integer result = null;
763
		if (nomenclaturalCode != null) {
764
			if (taxonName != null && taxonName.getRank() == null) {
765
				logger.warn("Rank is null: " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
766
			}
767
			result = PesiTransformer.rank2RankId(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
768
			if (result == null) {
769
				logger.warn("Rank could not be determined for PESI-Kingdom-Id " + PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode) + " and TaxonName " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + ")");
770
			}
771
		}
772
		return result;
773
	}
774

    
775
	/**
776
	 * Returns the <code>RankCache</code> attribute.
777
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
778
	 * @param nomenclaturalCode The {@link NomenclaturalCode NomenclaturalCode}.
779
	 * @param state
780
	 * @return The <code>RankCache</code> attribute.
781
	 * @see MethodMapper
782
	 */
783
	private static String getRankCache(TaxonNameBase taxonName, NomenclaturalCode nomenclaturalCode, PesiExportState state) {
784
		if (nomenclaturalCode != null) {
785
			return state.getTransformer().getCacheByRankAndKingdom(taxonName.getRank(), PesiTransformer.nomenClaturalCode2Kingdom(nomenclaturalCode));
786
		}else{
787
			logger.warn("No nomenclatural code defined for rank cache search");
788
			return null;
789
		}
790
	}
791

    
792
	/**
793
	 * Returns the CDM to PESI specific export mappings.
794
	 * @return The {@link PesiExportMapping PesiExportMapping}.
795
	 */
796
	PesiExportMapping getMapping() {
797
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
798

    
799
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
800
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
801
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
802
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
803
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
804

    
805
		return mapping;
806
	}
807

    
808
}
(9-9/12)