Project

General

Profile

Download (20.4 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.util.ArrayList;
14
import java.util.List;
15

    
16
import org.apache.log4j.Logger;
17
import org.springframework.stereotype.Component;
18
import org.springframework.transaction.TransactionStatus;
19

    
20
import eu.etaxonomy.cdm.io.common.Source;
21
import eu.etaxonomy.cdm.io.common.mapping.out.DbAnnotationMapper;
22
import eu.etaxonomy.cdm.io.common.mapping.out.DbFixedIntegerMapper;
23
import eu.etaxonomy.cdm.io.common.mapping.out.DbFixedStringMapper;
24
import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
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.TaxonName;
33
import eu.etaxonomy.cdm.model.taxon.Synonym;
34
import eu.etaxonomy.cdm.model.taxon.Taxon;
35
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
36
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
37
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
38

    
39
/**
40
 * The export class for relations between {@link eu.etaxonomy.cdm.model.taxon.TaxonBase TaxonBases}.<p>
41
 * Inserts into DataWarehouse database table <code>RelTaxon</code>.
42
 * @author e.-m.lee
43
 * @since 23.02.2010
44
 */
45
@Component
46
public class PesiRelTaxonExport extends PesiExportBase {
47

    
48
    private static final long serialVersionUID = 67808745337549629L;
49
    private static final Logger logger = Logger.getLogger(PesiRelTaxonExport.class);
50

    
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 PesiExportMapping mapping;
59
	private PesiExportMapping synonymMapping;
60
	private PesiExportMapping taxonNodeMapping;
61

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

    
66
	@Override
67
	public Class<? extends CdmBase> getStandardMethodParameter() {
68
		return standardMethodParameter;
69
	}
70

    
71
	@Override
72
	protected void doInvoke(PesiExportState state) {
73
		try {
74
			logger.info("*** Started Making " + pluralString + " ...");
75

    
76
			doDelete(state);
77

    
78
			Connection connection = state.getConfig().getDestination().getConnection();
79
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?";
80
			synonymsStmt = connection.prepareStatement(synonymsSql);
81

    
82
			// Stores whether this invoke was successful or not.
83
			boolean success = true;
84

    
85
			// PESI: Clear the database table RelTaxon.
86
			//doDelete(state); -> done by stored procedure
87

    
88
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
89
			mapping = getMapping();
90
			mapping.initialize(state);
91

    
92
			// Get specific mappings: (CDM) Synonym -> (PESI) RelTaxon
93
            synonymMapping = getSynonymMapping();
94
            synonymMapping.initialize(state);
95

    
96
            // Get specific mappings: (CDM) Synonym -> (PESI) RelTaxon
97
            taxonNodeMapping = getTaxonNodeMapping();
98
            taxonNodeMapping.initialize(state);
99

    
100

    
101
			//Export taxon relations
102
			success &= doPhase01(state, mapping);
103

    
104
			//Export taxon nodes
105
            success &= doPhase01b(state, taxonNodeMapping);
106

    
107
			// Export name relations
108
			success &= doPhase02(state, mapping);
109

    
110
	         // Export synonym relations (directly attached to taxa)
111
            success &= doPhase03(state, synonymMapping);
112

    
113
			if (! success){
114
				state.getResult().addError("An unknown error occurred in PesiRelTaxonExport");
115
			}
116
		} catch (Exception e) {
117
			e.printStackTrace();
118
			logger.error(e.getMessage());
119
			state.getResult().addException(e);
120
			return;
121
		}
122
	}
123

    
124
    private boolean doPhase03(PesiExportState state, PesiExportMapping synonymMapping) {
125
        logger.info("PHASE 3: Direct Synonym Relationships ...");
126

    
127
        boolean success = true;
128
        int limit = state.getConfig().getLimitSave();
129
        // Start transaction
130
        TransactionStatus txStatus = startTransaction(true);
131
        logger.debug("Started new transaction. Fetching some synonyms (max: " + limit + ") ...");
132

    
133
        List<Synonym> list;
134

    
135
        //taxon relations
136
        int partitionCount = 0;
137
        int totalCount = 0;
138
        while ((list = getNextTaxonPartition(Synonym.class, limit, partitionCount++, null))!= null) {
139
            totalCount = totalCount + list.size();
140
            logger.info("Read " + list.size() + " PESI synonyms. Limit: " + limit + ". Total: " + totalCount );
141
//          if (list.size() > 0){
142
//              logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
143
//          }
144
            for (Synonym synonym : list){
145
                try {
146
                    synonymMapping.invoke(synonym);
147
                } catch (Exception e) {
148
                    logger.error(e.getMessage() + ". Synonym: " +  synonym.getUuid());
149
                    e.printStackTrace();
150
                }
151
            }
152

    
153
            commitTransaction(txStatus);
154
            txStatus = startTransaction();
155
        }
156
        commitTransaction(txStatus);
157
        return success;
158
    }
159

    
160
    private boolean doPhase01(PesiExportState state, PesiExportMapping mapping) {
161
		logger.info("PHASE 1: Taxon Relationships ...");
162
		boolean success = true;
163

    
164
		int limit = state.getConfig().getLimitSave();
165
		// Start transaction
166
		TransactionStatus txStatus = startTransaction(true);
167
		logger.debug("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
168

    
169
		List<RelationshipBase<?,?,?>> list;
170

    
171
		//taxon relations
172
		int partitionCount = 0;
173
		int totalCount = 0;
174
		while ((list = getNextTaxonRelationshipPartition(limit, partitionCount++, null)) != null) {
175
			totalCount = totalCount + list.size();
176
			logger.info("Read " + list.size() + " PESI relations. Limit: " + limit + ". Total: " + totalCount );
177
//			if (list.size() > 0){
178
//				logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
179
//			}
180
			for (RelationshipBase<?,?,?> rel : list){
181
				try {
182
					mapping.invoke(rel);
183
				} catch (Exception e) {
184
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
185
					e.printStackTrace();
186
				}
187
			}
188

    
189
			commitTransaction(txStatus);
190
			txStatus = startTransaction();
191
		}
192
		commitTransaction(txStatus);
193
		return success;
194
	}
195

    
196
    private boolean doPhase01b(PesiExportState state, PesiExportMapping taxonNodeMapping) {
197
        logger.info("PHASE 1b: Taxonnodes ...");
198
        boolean success = true;
199

    
200
        int limit = state.getConfig().getLimitSave();
201
        // Start transaction
202
        TransactionStatus txStatus = startTransaction(true);
203
        logger.debug("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
204

    
205
        List<TaxonNode> list;
206

    
207
        //taxon nodes
208
        int partitionCount = 0;
209
        int totalCount = 0;
210
        while ((list = getNextTaxonNodePartition(limit, partitionCount++, null)) != null) {
211
            totalCount = totalCount + list.size();
212
            logger.info("Read " + list.size() + " PESI taxon nodes. Limit: " + limit + ". Total: " + totalCount );
213
            for (TaxonNode tn : list){
214
                try {
215
                    taxonNodeMapping.invoke(tn);
216
                } catch (Exception e) {
217
                    logger.error(e.getMessage() + ". TaxonNode: " +  tn.getUuid());
218
                    e.printStackTrace();
219
                }
220
            }
221

    
222
            commitTransaction(txStatus);
223
            txStatus = startTransaction();
224
        }
225
        commitTransaction(txStatus);
226
        return success;
227
    }
228

    
229
	private boolean doPhase02(PesiExportState state, PesiExportMapping mapping2) {
230
		logger.info("PHASE 2: Name Relationships ...");
231
		boolean success = true;
232

    
233
		int limit = state.getConfig().getLimitSave();
234
		// Start transaction
235
		TransactionStatus txStatus = startTransaction(true);
236
		logger.debug("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
237

    
238
		//name relations
239
		List<NameRelationship> list;
240
		int partitionCount = 0;
241
		while ((list = getNextNameRelationshipPartition(NameRelationship.class, limit, partitionCount++, null)) != null   ) {
242
			txStatus = handleNameRelationList(state, txStatus, list);
243
		}
244
        //hybrid relations
245
		List<HybridRelationship> hybridList;
246
		partitionCount = 0;
247
        while ((hybridList = getNextNameRelationshipPartition(HybridRelationship.class, limit, partitionCount++, null)) != null   ) {
248
            txStatus = handleNameRelationList(state, txStatus, hybridList);
249
        }
250
        commitTransaction(txStatus);
251
		logger.info("End PHASE 2: Name Relationships ...");
252
		state.setCurrentFromObject(null);
253
		state.setCurrentToObject(null);
254
		return success;
255
	}
256

    
257
    private TransactionStatus handleNameRelationList(PesiExportState state, TransactionStatus txStatus,
258
            List<? extends RelationshipBase<?,?,?>> list) {
259
        for (RelationshipBase<?,?,?> rel : list){
260
        	try {
261
        	    TaxonName name1;
262
        	    TaxonName name2;
263
        		if (rel.isInstanceOf(HybridRelationship.class)){
264
        			HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
265
        			name1 = hybridRel.getParentName();
266
        			name2 = hybridRel.getHybridName();
267
        		}else if (rel.isInstanceOf(NameRelationship.class)){
268
        			NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
269
        			name1 = nameRel.getFromName();
270
        			name2 = nameRel.getToName();
271
        		}else{
272
        			logger.warn ("Only hybrid- and name-relationships allowed here");
273
        			continue;
274
        		}
275
        		List<IdentifiableEntity> fromList = new ArrayList<>();
276
        		List<IdentifiableEntity> toList = new ArrayList<>();
277
        		makeList(name1, fromList);
278
        		makeList(name2, toList);
279

    
280
        		for (IdentifiableEntity<?> fromEntity : fromList){
281
        			for (IdentifiableEntity<?> toEntity : toList){
282
        				//TODO set entities to state
283
        				state.setCurrentFromObject(fromEntity);
284
        				state.setCurrentToObject(toEntity);
285
        				mapping.invoke(rel);
286
        			}
287
        		}
288
        		fromList = null;
289
        		toList = null;
290

    
291
        	} catch (Exception e) {
292
        		logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
293
        		e.printStackTrace();
294
        	}
295
        }
296
        commitTransaction(txStatus);
297
        txStatus = startTransaction();
298
        return txStatus;
299
    }
300

    
301
	private void makeList(TaxonName name, List<IdentifiableEntity> list) {
302
		if (! hasPesiTaxon(name)){
303
			list.add(name);
304
		}else{
305
			for (TaxonBase<?> taxon:  getPesiTaxa(name)){
306
				list.add(taxon);
307
			}
308
		}
309
	}
310

    
311
	/**
312
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
313
	 * @param state The {@link PesiExportState PesiExportState}.
314
	 * @return Whether the delete operation was successful or not.
315
	 */
316
	protected boolean doDelete(PesiExportState state) {
317
		PesiExportConfigurator pesiConfig = state.getConfig();
318

    
319
		Source destination =  pesiConfig.getDestination();
320

    
321
		// Clear RelTaxon
322
		String sql = "DELETE FROM " + dbTableName;
323
		destination.update(sql);
324
		return true;
325
	}
326

    
327
	/**
328
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
329
	 * @param relationship The {@link RelationshipBase Relationship}.
330
	 * @param state The {@link PesiExportState PesiExportState}.
331
	 * @return The <code>TaxonFk1</code> attribute.
332
	 * @see MethodMapper
333
	 */
334
    @SuppressWarnings("unused")
335
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
336
		return getObjectFk(relationship, state, true);
337
	}
338

    
339
	/**
340
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
341
     * @param relationship The {@link RelationshipBase Relationship}.
342
     * @param state The {@link PesiExportState PesiExportState}.
343
     * @return The <code>TaxonFk1</code> attribute.
344
     * @see MethodMapper
345
     */
346
    @SuppressWarnings("unused")
347
    private static Integer getTaxonFk1(Synonym synonym, PesiExportState state) {
348
        return synonym.getAcceptedTaxon().getId();
349
    }
350
    /**
351
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>Synonym</code>.
352
     * @param synonym The {@link Synonym synonym}.
353
     * @param state The {@link PesiExportState PesiExportState}.
354
     * @return The <code>TaxonFk1</code> attribute.
355
     * @see MethodMapper
356
     */
357
    @SuppressWarnings("unused")
358
    private static Integer getSynonym(Synonym synonym, PesiExportState state) {
359
        return state.getDbId(synonym);
360
    }
361

    
362
    /**
363
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>Synonym</code>.
364
     * @param synonym The {@link Synonym synonym}.
365
     * @param state The {@link PesiExportState PesiExportState}.
366
     * @return The <code>TaxonFk1</code> attribute.
367
     * @see MethodMapper
368
     */
369
    @SuppressWarnings("unused")
370
    private static Integer getParent(TaxonNode taxonNode, PesiExportState state) {
371
        TaxonNode parent = taxonNode == null? null : taxonNode.getParent();
372
        Taxon parentTaxon = parent == null? null: parent.getTaxon();
373
        return state.getDbId(parentTaxon);
374
    }
375

    
376
	/**
377
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
378
	 * @param relationship The {@link RelationshipBase Relationship}.
379
	 * @param state The {@link PesiExportState PesiExportState}.
380
	 * @return The <code>TaxonFk2</code> attribute.
381
	 * @see MethodMapper
382
	 */
383
    @SuppressWarnings("unused")
384
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
385
		return getObjectFk(relationship, state, false);
386
	}
387

    
388
	/**
389
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
390
	 * @param relationship The {@link RelationshipBase Relationship}.
391
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
392
	 * @see MethodMapper
393
	 */
394
	@SuppressWarnings("unused")
395
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
396
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
397
	}
398

    
399
    @SuppressWarnings("unused")
400
    private static Integer getRelTaxonQualifierFk(Synonym synonym) {
401
        return PesiTransformer.synonym2RelTaxonQualifierFk(synonym);
402
    }
403

    
404
	/**
405
	 * Returns the <code>RelQualifierCache</code> attribute.
406
	 * @param relationship The {@link RelationshipBase Relationship}.
407
	 * @return The <code>RelQualifierCache</code> attribute.
408
	 * @see MethodMapper
409
	 */
410
	@SuppressWarnings("unused")
411
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
412
		String result = null;
413
		NomenclaturalCode code = null;
414
		Taxon taxon = null;
415
		TaxonName name= null;
416
		if (relationship.isInstanceOf(TaxonRelationship.class)){
417
			TaxonRelationship rel = CdmBase.deproxy(relationship, TaxonRelationship.class);
418
			taxon = rel.getToTaxon();
419
			name = taxon.getName();
420
			code = name.getNameType();
421
		}else if (relationship.isInstanceOf(NameRelationship.class)){
422
			NameRelationship rel = CdmBase.deproxy(relationship,  NameRelationship.class);
423
			name = rel.getFromName();
424
			code =name.getNameType();
425
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
426
			HybridRelationship rel =  CdmBase.deproxy(relationship,  HybridRelationship.class);
427
			name = rel.getParentName();
428
			code = name.getNameType();
429
		}
430
		if (code != null) {
431
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
432
		} else {
433
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
434
		}
435
		return result;
436
	}
437

    
438

    
439
	/**
440
	 * Returns the database key of an object in the given relationship.
441
	 * @param relationship {@link RelationshipBase RelationshipBase}.
442
	 * @param state {@link PesiExportState PesiExportState}.
443
	 * @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.
444
	 * @return The database key of an object in the given relationship.
445
	 */
446
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
447
		TaxonBase<?> taxonBase = null;
448
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
449
			TaxonRelationship tr = (TaxonRelationship)relationship;
450
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
451
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
452
			if (isFrom){
453
				return state.getDbId(state.getCurrentFromObject());
454
			}else{
455
				return state.getDbId(state.getCurrentToObject());
456
			}
457
		}
458
		if (taxonBase != null) {
459
			if (! isPesiTaxon(taxonBase)){
460
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
461
				return null;
462
			}else{
463
				return state.getDbId(taxonBase);
464
			}
465

    
466
		}
467
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
468
		return null;
469
	}
470

    
471
    @SuppressWarnings("unused")  //for synonym mapping
472
    private static String getSynonymTypeCache(Synonym synonym, PesiExportState state) {
473
        String result = null;
474
        NomenclaturalCode code = null;
475
        code = synonym.getAcceptedTaxon().getName().getNameType();
476

    
477
        if (code != null) {
478
            result = state.getConfig().getTransformer().getCacheBySynonymType(synonym, code);
479
        } else {
480
            logger.error("NomenclaturalCode is NULL while creating the following synonym: " + synonym.getUuid());
481
        }
482
        return result;
483
    }
484

    
485
	/**
486
	 * Returns the CDM to PESI specific export mappings.
487
	 * @return The {@link PesiExportMapping PesiExportMapping}.
488
	 */
489
	PesiExportMapping getMapping() {
490
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
491

    
492
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
493
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
494
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
495
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
496
		mapping.addMapper(DbAnnotationMapper.NewExludedInstance(getLastActionAnnotationTypes(), "Notes"));
497

    
498
		return mapping;
499
	}
500

    
501
	   /**
502
     * Returns the CDM to PESI specific export mappings.
503
     * @return The {@link PesiExportMapping PesiExportMapping}.
504
     */
505
    PesiExportMapping getSynonymMapping() {
506
        PesiExportMapping mapping = new PesiExportMapping(dbTableName);
507

    
508
        mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getSynonym", Synonym.class, PesiExportState.class));
509
        mapping.addMapper(DbObjectMapper.NewInstance("acceptedTaxon", "TaxonFk2"));
510
        mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this, Synonym.class));
511
        mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this.getClass(), "getSynonymTypeCache", Synonym.class, PesiExportState.class));
512
        mapping.addMapper(DbAnnotationMapper.NewExludedInstance(getLastActionAnnotationTypes(), "Notes"));
513

    
514
        return mapping;
515
    }
516

    
517
    PesiExportMapping getTaxonNodeMapping() {
518
        PesiExportMapping mapping = new PesiExportMapping(dbTableName);
519

    
520
        mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getParent", TaxonNode.class, PesiExportState.class));
521
        mapping.addMapper(DbObjectMapper.NewInstance("taxon", "TaxonFk1"));
522
        mapping.addMapper(DbFixedIntegerMapper.NewInstance(101, "RelTaxonQualifierFk"));
523
        mapping.addMapper(DbFixedStringMapper.NewInstance("is taxonomically included in", "RelQualifierCache"));
524
//        mapping.addMapper(DbAnnotationMapper.NewExludedInstance(getLastActionAnnotationTypes(), "Notes"));
525

    
526
        return mapping;
527
    }
528

    
529

    
530

    
531
    @Override
532
    protected boolean doCheck(PesiExportState state) {
533
        return true;
534
    }
535

    
536
    @Override
537
    protected boolean isIgnore(PesiExportState state) {
538
        return ! state.getConfig().isDoRelTaxa();
539
    }
540
}
(11-11/14)