Project

General

Profile

« Previous | Next » 

Revision 9bfdad13

Added by Andreas Müller over 8 years ago

use listRankSpecificRootNodes instead of deprecated methods

View differences:

cdm-pesi/src/main/java/eu/etaxonomy/cdm/io/pesi/out/PesiRelTaxonExport.java
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); -> done by stored procedure
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
			if (! success){
118
				state.setUnsuccessfull();
119
			}
120

  
121
		} catch (SQLException e) {
122
			e.printStackTrace();
123
			logger.error(e.getMessage());
124
			state.setUnsuccessfull();
125
			return;
126
		}
127
	}
128
	
129
	
130
	private boolean doPhase01(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
131
		logger.info("PHASE 1: Taxon Relationships ...");
132
		boolean success = true;
133
		
134
		int limit = state.getConfig().getLimitSave();
135
		// Start transaction
136
		TransactionStatus txStatus = startTransaction(true);
137
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
138
		
139
		List<RelationshipBase> list;
140
		
141
		//taxon relations
142
		int partitionCount = 0;
143
		int totalCount = 0;
144
		while ((list = getNextTaxonRelationshipPartition( limit, partitionCount++, null)) != null ) {
145
			totalCount = totalCount + list.size();
146
			logger.info("Read " + list.size() + " PESI relations. Limit: " + limit + ". Total: " + totalCount );
147
//			if (list.size() > 0){
148
//				logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
149
//			}
150
			for (RelationshipBase rel : list){
151
				try {
152
					mapping.invoke(rel);
153
				} catch (Exception e) {
154
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
155
					e.printStackTrace();
156
				}
157
			}
158
			
159
			commitTransaction(txStatus);
160
			txStatus = startTransaction();
161
		}
162
		list = null;
163
		commitTransaction(txStatus);
164
		return success;
165
	}
166
	
167
	private boolean doPhase02(PesiExportState state, PesiExportMapping mapping2) throws SQLException {
168
		logger.info("PHASE 2: Name Relationships ...");
169
		boolean success = true;
170
		
171
		int limit = state.getConfig().getLimitSave();
172
		// Start transaction
173
		TransactionStatus txStatus = startTransaction(true);
174
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
175
		
176
		List<RelationshipBase> list;
177
		
178
		//name relations
179
		int partitionCount = 0;
180
		while ((list = getNextNameRelationshipPartition(null, limit, partitionCount++, null)) != null   ) {
181
			for (RelationshipBase rel : list){
182
				try {
183
					TaxonNameBase<?,?> name1;
184
					TaxonNameBase<?,?> name2;
185
					if (rel.isInstanceOf(HybridRelationship.class)){
186
						HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
187
						name1 = hybridRel.getParentName();
188
						name2 = hybridRel.getHybridName();
189
						hybridRel = null;
190
					}else if (rel.isInstanceOf(NameRelationship.class)){
191
						NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
192
						name1 = nameRel.getFromName();
193
						name2 = nameRel.getToName();
194
						nameRel = null;
195
					}else{
196
						logger.warn ("Only hybrid- and name-relationships alowed here");
197
						continue;
198
					}
199
					List<IdentifiableEntity> fromList = new ArrayList<IdentifiableEntity>();
200
					List<IdentifiableEntity> toList = new ArrayList<IdentifiableEntity>();
201
					makeList(name1, fromList);
202
					makeList(name2, toList);
203
					
204
					for (IdentifiableEntity fromEntity : fromList){
205
						for (IdentifiableEntity toEntity : toList){
206
							//TODO set entities to state
207
							state.setCurrentFromObject(fromEntity);
208
							state.setCurrentToObject(toEntity);
209
							mapping.invoke(rel);
210
						}
211
					}
212
					fromList = null;
213
					toList = null;
214
					name1 = null;
215
					name2 = null;
216
					rel = null;
217
					
218
					
219
				} catch (Exception e) {
220
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
221
					e.printStackTrace();
222
				}
223
			}
224
			commitTransaction(txStatus);
225
			txStatus = startTransaction();
226
		}
227
		commitTransaction(txStatus);
228
		list = null;
229
		logger.info("End PHASE 2: Name Relationships ...");
230
		state.setCurrentFromObject(null);
231
		state.setCurrentToObject(null);	
232
		return success;
233
	}
234

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

  
245
	/* (non-Javadoc)
246
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
247
	 */
248
	protected void doInvoke_Old(PesiExportState state) {
249
		try {
250
			logger.info("*** Started Making " + pluralString + " ...");
251
	
252
			Connection connection = state.getConfig().getDestination().getConnection();
253
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?"; 
254
			synonymsStmt = connection.prepareStatement(synonymsSql);
255

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

  
259
			// PESI: Clear the database table RelTaxon.
260
			doDelete(state);
261
	
262
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
263
			mapping = getMapping();
264

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

  
268
			TransactionStatus txStatus = null;
269
			List<Classification> classificationList = null;
270
			
271
			// Specify starting ranks for tree traversing
272
			rankList.add(Rank.KINGDOM());
273
			rankList.add(Rank.GENUS());
274

  
275
			// Specify where to stop traversing (value) when starting at a specific Rank (key)
276
			rank2endRankMap.put(Rank.GENUS(), null); // Since NULL does not match an existing Rank, traverse all the way down to the leaves
277
			rank2endRankMap.put(Rank.KINGDOM(), Rank.GENUS()); // excludes rank genus
278
			
279
			// Retrieve list of classifications
280
			txStatus = startTransaction(true);
281
			logger.info("Started transaction. Fetching all classifications...");
282
			classificationList = getClassificationService().listClassifications(null, 0, null, null);
283
			commitTransaction(txStatus);
284
			logger.debug("Committed transaction.");
285

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

  
288
			for (Classification classification : classificationList) {
289
				for (Rank rank : rankList) {
290
					
291
					txStatus = startTransaction(true);
292
					logger.info("Started transaction to fetch all rootNodes specific to Rank " + rank.getLabel() + " ...");
293

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

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

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

  
307
						if (isPesiTaxon(newNode.getTaxon())){
308
							
309
							TaxonNode parentNode = newNode.getParent();
310
	
311
							success &=traverseTree(newNode, parentNode, endRank, state);
312
	
313
							commitTransaction(txStatus);
314
							logger.debug("Committed transaction.");
315
						}else{
316
							logger.debug("Taxon is not in PESI");
317
						}
318

  
319
					}
320
				}
321
			}
322

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

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

  
337
	/**
338
	 * Traverses the classification recursively and stores determined values for every Taxon.
339
	 * @param childNode
340
	 * @param parentNode
341
	 * @param treeIndex
342
	 * @param fetchLevel
343
	 * @param state
344
	 */
345
	private boolean  traverseTree(TaxonNode childNode, TaxonNode parentNode, Rank fetchLevel, PesiExportState state) {
346
		boolean success = true;
347
		// Traverse all branches from this childNode until specified fetchLevel is reached.
348
		TaxonBase<?> childTaxon = childNode.getTaxon();
349
		if (childTaxon != null) {
350
			if (isPesiTaxon(childTaxon)){
351
				if (childTaxon.getName() != null) {
352
					Rank childTaxonNameRank = childTaxon.getName().getRank();
353
					if (childTaxonNameRank != null) {
354
						if (! childTaxonNameRank.equals(fetchLevel)) {
355
	
356
							success &= saveData(childNode, parentNode, state);
357
	
358
							for (TaxonNode newNode : childNode.getChildNodes()) {
359
								success &= traverseTree(newNode, childNode, fetchLevel, state);
360
							}
361
							
362
						} else {
363
	//						logger.error("Target Rank " + fetchLevel.getLabel() + " reached");
364
							return success;
365
						}
366
					} else {
367
						logger.warn("Rank is NULL. FetchLevel can not be checked: " + childTaxon.getUuid() + " (" + childTaxon.getTitleCache() + ")");
368
					}
369
				} else {
370
					logger.error("TaxonName is NULL for taxon: " + childTaxon.getUuid());
371
				}
372
			}else{
373
				logger.debug("Taxon is not a PESI taxon: " + childTaxon.getUuid());
374
			}
375

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

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

  
405
	private boolean saveSynonymAndSynNameRelationships(PesiExportState state, Taxon childNodeTaxon) {
406
		boolean success = true;
407
		for (SynonymRelationship synRel : childNodeTaxon.getSynonymRelations()) { // synonyms of accepted taxon
408
			Synonym synonym = synRel.getSynonym();
409
			TaxonNameBase<?,?> synonymTaxonName = synonym.getName();
410
			if (! isPesiTaxon(synonym)){
411
				logger.warn("Synonym " + synonym.getId() + " of synonym relation " + synRel.getId() + " is not a PESI taxon. Can't export relationship");
412
				continue;
413
			}
414
			
415
			// Store synonym data in Taxon table
416
			invokeSynonyms(state, synonymTaxonName);
417

  
418
			
419
			
420
			Set<SynonymRelationship> synonymRelations = synonym.getSynonymRelations();
421
			state.setCurrentFromObject(synonym);
422
			for (SynonymRelationship synonymRelationship : synonymRelations) {  //needed? Maybe to make sure that there are no partial synonym relations missed ??
423
				try {
424
					if (neededValuesNotNull(synonymRelationship, state)) {
425
						doCount(count++, modCount, pluralString);
426
						success &= mapping.invoke(synonymRelationship);
427
						
428
					}
429
				} catch (SQLException e) {
430
					logger.error("SynonymRelationship (" + synonymRelationship.getUuid() + ") could not be stored : " + e.getMessage());
431
				}
432
			}
433

  
434
			// SynonymNameRelationship
435
			success &= saveNameRelationships(state, synonym);
436
		}
437
		state.setCurrentFromObject(null);
438
		return success;
439
	}
440

  
441
	private boolean saveNameRelationships(PesiExportState state, TaxonBase taxonBase) {
442
		boolean success = true;
443
		TaxonNameBase<?,?> childNodeTaxonName = taxonBase.getName();
444

  
445
		//from relations
446
		Set<NameRelationship> nameRelations = childNodeTaxonName.getRelationsFromThisName();
447
		state.setCurrentFromObject(taxonBase);
448
		boolean isFrom = true;
449
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
450
		
451
		//toRelations
452
		nameRelations = childNodeTaxonName.getRelationsToThisName();
453
		state.setCurrentToObject(taxonBase);
454
		isFrom = false;
455
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
456
		state.setCurrentToObject(null);
457
		return success;
458
	}
459

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

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

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

  
513
	/**
514
	 * Determines synonym related data and saves them.
515
	 * @param state
516
	 * @param sr
517
	 */
518
	private void invokeSynonyms(PesiExportState state, TaxonNameBase synonymTaxonName) {
519
		// Store KingdomFk and Rank information in Taxon table
520
		Integer kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(synonymTaxonName.getNomenclaturalCode());
521
		Integer synonymFk = state.getDbId(synonymTaxonName);
522

  
523
		saveSynonymData(state, synonymTaxonName, synonymTaxonName.getNomenclaturalCode(), kingdomFk, synonymFk);
524
	}
525

  
526
	/**
527
	 * Stores synonym data.
528
	 * @param state 
529
	 * @param taxonName
530
	 * @param nomenclaturalCode
531
	 * @param kingdomFk
532
	 * @param synonymParentTaxonFk
533
	 * @param currentTaxonFk
534
	 */
535
	private boolean saveSynonymData(PesiExportState state, TaxonNameBase taxonName,
536
			NomenclaturalCode nomenclaturalCode, Integer kingdomFk,
537
			Integer currentSynonymFk) {
538
		try {
539
			if (kingdomFk != null) {
540
				synonymsStmt.setInt(1, kingdomFk);
541
			} else {
542
				synonymsStmt.setObject(1, null);
543
			}
544
			
545
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
546
			if (rankFk != null) {
547
				synonymsStmt.setInt(2, rankFk);
548
			} else {
549
				synonymsStmt.setObject(2, null);
550
			}
551
			synonymsStmt.setString(3, getRankCache(taxonName, nomenclaturalCode, state));
552
			
553
			if (currentSynonymFk != null) {
554
				synonymsStmt.setInt(4, currentSynonymFk);
555
			} else {
556
				synonymsStmt.setObject(4, null);
557
			}
558
			synonymsStmt.executeUpdate();
559
			return true;
560
		} catch (SQLException e) {
561
			logger.error("SQLException during invoke for taxonName - " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + "): " + e.getMessage());
562
			e.printStackTrace();
563
			return false;
564
		}
565
	}
566

  
567
	/**
568
	 * Checks whether needed values for an entity are NULL.
569
	 * @return
570
	 */
571
	private boolean neededValuesNotNull(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
572
		boolean result = true;
573
		if (getTaxonFk1(relationship, state) == null) {
574
			logger.warn("TaxonFk1 is NULL, but is not allowed to be. Therefore no record was written to export database for this relationship: " + relationship.getUuid());
575
			result = false;
576
		}
577
		if (getTaxonFk2(relationship, state) == null) {
578
			logger.warn("TaxonFk2 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
		return result;
582
	}
583
	
584
	/**
585
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
586
	 * @param state The {@link PesiExportState PesiExportState}.
587
	 * @return Whether the delete operation was successful or not.
588
	 */
589
	protected boolean doDelete(PesiExportState state) {
590
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
591
		
592
		String sql;
593
		Source destination =  pesiConfig.getDestination();
594

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

  
602
	/* (non-Javadoc)
603
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
604
	 */
605
	@Override
606
	protected boolean isIgnore(PesiExportState state) {
607
		return ! state.getConfig().isDoRelTaxa();
608
	}
609

  
610
	/**
611
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
612
	 * @param relationship The {@link RelationshipBase Relationship}.
613
	 * @param state The {@link PesiExportState PesiExportState}.
614
	 * @return The <code>TaxonFk1</code> attribute.
615
	 * @see MethodMapper
616
	 */
617
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
618
		return getObjectFk(relationship, state, true);
619
	}
620
	
621
	/**
622
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
623
	 * @param relationship The {@link RelationshipBase Relationship}.
624
	 * @param state The {@link PesiExportState PesiExportState}.
625
	 * @return The <code>TaxonFk2</code> attribute.
626
	 * @see MethodMapper
627
	 */
628
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
629
		return getObjectFk(relationship, state, false);
630
	}
631
	
632
	/**
633
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
634
	 * @param relationship The {@link RelationshipBase Relationship}.
635
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
636
	 * @see MethodMapper
637
	 */
638
	@SuppressWarnings("unused")
639
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
640
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
641
	}
642
	
643
	/**
644
	 * Returns the <code>RelQualifierCache</code> attribute.
645
	 * @param relationship The {@link RelationshipBase Relationship}.
646
	 * @return The <code>RelQualifierCache</code> attribute.
647
	 * @see MethodMapper
648
	 */
649
	@SuppressWarnings("unused")
650
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
651
		String result = null;
652
		NomenclaturalCode code = null;
653
		Taxon taxon = null;
654
		TaxonNameBase name= null;
655
		if (relationship.isInstanceOf(TaxonRelationship.class)){
656
			TaxonRelationship rel = CdmBase.deproxy(relationship, TaxonRelationship.class);
657
			taxon = rel.getToTaxon();
658
			name = taxon.getName();
659
			code = name.getNomenclaturalCode();
660
			rel = null;
661
			
662
		}else if (relationship.isInstanceOf(SynonymRelationship.class)){
663
			SynonymRelationship rel = CdmBase.deproxy(relationship, SynonymRelationship.class);
664
			taxon = rel.getAcceptedTaxon();
665
			name = taxon.getName();
666
			code = name.getNomenclaturalCode();
667
			rel = null;
668

  
669
		}else if (relationship.isInstanceOf(NameRelationship.class)){
670
			NameRelationship rel = CdmBase.deproxy(relationship,  NameRelationship.class);
671
			name = rel.getFromName();
672
			code =name.getNomenclaturalCode();
673
			rel = null;
674
						
675
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
676
			HybridRelationship rel =  CdmBase.deproxy(relationship,  HybridRelationship.class);
677
			name = rel.getParentName();
678
			code = name.getNomenclaturalCode();
679
			rel = null;
680
		}
681
		taxon = null;
682
		name = null;
683
		if (code != null) {
684
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
685
		} else {
686
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
687
		}
688
		return result;
689
	}
690
	
691
	/**
692
	 * Returns the <code>Notes</code> attribute.
693
	 * @param relationship The {@link RelationshipBase Relationship}.
694
	 * @return The <code>Notes</code> attribute.
695
	 * @see MethodMapper
696
	 */
697
	@SuppressWarnings("unused")
698
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
699
		// TODO
700
		return null;
701
	}
702

  
703
	/**
704
	 * Returns the database key of an object in the given relationship.
705
	 * @param relationship {@link RelationshipBase RelationshipBase}.
706
	 * @param state {@link PesiExportState PesiExportState}.
707
	 * @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.
708
	 * @return The database key of an object in the given relationship.
709
	 */
710
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
711
		TaxonBase<?> taxonBase = null;
712
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
713
			TaxonRelationship tr = (TaxonRelationship)relationship;
714
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
715
		} else if (relationship.isInstanceOf(SynonymRelationship.class)) {
716
			SynonymRelationship sr = (SynonymRelationship)relationship;
717
			taxonBase = (isFrom) ? sr.getSynonym() : sr.getAcceptedTaxon();
718
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
719
			if (isFrom){
720
				return state.getDbId(state.getCurrentFromObject());
721
			}else{
722
				return state.getDbId(state.getCurrentToObject());
723
			}
724
		}
725
		if (taxonBase != null) {
726
			if (! isPesiTaxon(taxonBase)){
727
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
728
				return null;
729
			}else{
730
				return state.getDbId(taxonBase);	
731
			}
732
			
733
		}
734
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
735
		return null;
736
	}
737

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

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

  
776
	/**
777
	 * Returns the CDM to PESI specific export mappings.
778
	 * @return The {@link PesiExportMapping PesiExportMapping}.
779
	 */
780
	PesiExportMapping getMapping() {
781
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
782
		
783
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
784
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
785
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
786
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
787
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
788

  
789
		return mapping;
790
	}
791

  
792
}
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 final HashMap<Rank, Rank> rank2endRankMap = new HashMap<Rank, Rank>();
60
	private final 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); -> done by stored procedure
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
			if (! success){
118
				state.setUnsuccessfull();
119
			}
120

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

  
129

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

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

  
139
		List<RelationshipBase> list;
140

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

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

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

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

  
176
		List<RelationshipBase> list;
177

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

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

  
218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  
309
							TaxonNode parentNode = newNode.getParent();
310

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

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

  
319
					}
320
				}
321
			}
322

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

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

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

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

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

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

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

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

  
403
	}
404

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

  
415
			// Store synonym data in Taxon table
416
			invokeSynonyms(state, synonymTaxonName);
417

  
418

  
419

  
420
			Set<SynonymRelationship> synonymRelations = synonym.getSynonymRelations();
421
			state.setCurrentFromObject(synonym);
422
			for (SynonymRelationship synonymRelationship : synonymRelations) {  //needed? Maybe to make sure that there are no partial synonym relations missed ??
423
				try {
424
					if (neededValuesNotNull(synonymRelationship, state)) {
425
						doCount(count++, modCount, pluralString);
426
						success &= mapping.invoke(synonymRelationship);
427

  
428
					}
429
				} catch (SQLException e) {
430
					logger.error("SynonymRelationship (" + synonymRelationship.getUuid() + ") could not be stored : " + e.getMessage());
431
				}
432
			}
433

  
434
			// SynonymNameRelationship
435
			success &= saveNameRelationships(state, synonym);
436
		}
437
		state.setCurrentFromObject(null);
438
		return success;
439
	}
440

  
441
	private boolean saveNameRelationships(PesiExportState state, TaxonBase taxonBase) {
442
		boolean success = true;
443
		TaxonNameBase<?,?> childNodeTaxonName = taxonBase.getName();
444

  
445
		//from relations
446
		Set<NameRelationship> nameRelations = childNodeTaxonName.getRelationsFromThisName();
447
		state.setCurrentFromObject(taxonBase);
448
		boolean isFrom = true;
449
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
450

  
451
		//toRelations
452
		nameRelations = childNodeTaxonName.getRelationsToThisName();
453
		state.setCurrentToObject(taxonBase);
454
		isFrom = false;
455
		success &= saveOneSideNameRelation(state, isFrom, nameRelations);
456
		state.setCurrentToObject(null);
457
		return success;
458
	}
459

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

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

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

  
513
	/**
514
	 * Determines synonym related data and saves them.
515
	 * @param state
516
	 * @param sr
517
	 */
518
	private void invokeSynonyms(PesiExportState state, TaxonNameBase synonymTaxonName) {
519
		// Store KingdomFk and Rank information in Taxon table
520
		Integer kingdomFk = PesiTransformer.nomenClaturalCode2Kingdom(synonymTaxonName.getNomenclaturalCode());
521
		Integer synonymFk = state.getDbId(synonymTaxonName);
522

  
523
		saveSynonymData(state, synonymTaxonName, synonymTaxonName.getNomenclaturalCode(), kingdomFk, synonymFk);
524
	}
525

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

  
545
			Integer rankFk = getRankFk(taxonName, nomenclaturalCode);
546
			if (rankFk != null) {
547
				synonymsStmt.setInt(2, rankFk);
548
			} else {
549
				synonymsStmt.setObject(2, null);
550
			}
551
			synonymsStmt.setString(3, getRankCache(taxonName, nomenclaturalCode, state));
552

  
553
			if (currentSynonymFk != null) {
554
				synonymsStmt.setInt(4, currentSynonymFk);
555
			} else {
556
				synonymsStmt.setObject(4, null);
557
			}
558
			synonymsStmt.executeUpdate();
559
			return true;
560
		} catch (SQLException e) {
561
			logger.error("SQLException during invoke for taxonName - " + taxonName.getUuid() + " (" + taxonName.getTitleCache() + "): " + e.getMessage());
562
			e.printStackTrace();
563
			return false;
564
		}
565
	}
566

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

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

  
592
		String sql;
593
		Source destination =  pesiConfig.getDestination();
594

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

  
602
	/* (non-Javadoc)
603
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
604
	 */
605
	@Override
606
	protected boolean isIgnore(PesiExportState state) {
607
		return ! state.getConfig().isDoRelTaxa();
608
	}
609

  
610
	/**
611
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
612
	 * @param relationship The {@link RelationshipBase Relationship}.
613
	 * @param state The {@link PesiExportState PesiExportState}.
614
	 * @return The <code>TaxonFk1</code> attribute.
615
	 * @see MethodMapper
616
	 */
617
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
618
		return getObjectFk(relationship, state, true);
619
	}
620

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

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

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

  
662
		}else if (relationship.isInstanceOf(SynonymRelationship.class)){
663
			SynonymRelationship rel = CdmBase.deproxy(relationship, SynonymRelationship.class);
664
			taxon = rel.getAcceptedTaxon();
665
			name = taxon.getName();
666
			code = name.getNomenclaturalCode();
667
			rel = null;
668

  
669
		}else if (relationship.isInstanceOf(NameRelationship.class)){
670
			NameRelationship rel = CdmBase.deproxy(relationship,  NameRelationship.class);
671
			name = rel.getFromName();
672
			code =name.getNomenclaturalCode();
673
			rel = null;
674

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

  
691
	/**
692
	 * Returns the <code>Notes</code> attribute.
693
	 * @param relationship The {@link RelationshipBase Relationship}.
694
	 * @return The <code>Notes</code> attribute.
695
	 * @see MethodMapper
696
	 */
697
	@SuppressWarnings("unused")
698
	private static String getNotes(RelationshipBase<?, ?, ?> relationship) {
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff