Project

General

Profile

Download (17.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.DbObjectMapper;
23
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
24
import eu.etaxonomy.cdm.model.common.CdmBase;
25
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
26
import eu.etaxonomy.cdm.model.common.RelationshipBase;
27
import eu.etaxonomy.cdm.model.name.HybridRelationship;
28
import eu.etaxonomy.cdm.model.name.NameRelationship;
29
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
30
import eu.etaxonomy.cdm.model.name.TaxonName;
31
import eu.etaxonomy.cdm.model.taxon.Synonym;
32
import eu.etaxonomy.cdm.model.taxon.Taxon;
33
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
34
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
35

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

    
45
    private static final long serialVersionUID = 67808745337549629L;
46
    private static final Logger logger = Logger.getLogger(PesiRelTaxonExport.class);
47

    
48
    private static final Class<? extends CdmBase> standardMethodParameter = RelationshipBase.class;
49

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

    
55
	private PesiExportMapping mapping;
56
	private PesiExportMapping synonymMapping;
57

    
58
	public PesiRelTaxonExport() {
59
		super();
60
	}
61

    
62
	@Override
63
	public Class<? extends CdmBase> getStandardMethodParameter() {
64
		return standardMethodParameter;
65
	}
66

    
67
	@Override
68
	protected void doInvoke(PesiExportState state) {
69
		try {
70
			logger.info("*** Started Making " + pluralString + " ...");
71

    
72
			doDelete(state);
73

    
74
			Connection connection = state.getConfig().getDestination().getConnection();
75
			String synonymsSql = "UPDATE Taxon SET KingdomFk = ?, RankFk = ?, RankCache = ? WHERE TaxonId = ?";
76
			synonymsStmt = connection.prepareStatement(synonymsSql);
77

    
78
			// Stores whether this invoke was successful or not.
79
			boolean success = true;
80

    
81
			// PESI: Clear the database table RelTaxon.
82
			//doDelete(state); -> done by stored procedure
83

    
84
			// Get specific mappings: (CDM) Relationship -> (PESI) RelTaxon
85
			mapping = getMapping();
86
			mapping.initialize(state);
87

    
88
			// Get specific mappings: (CDM) Synonym -> (PESI) RelTaxon
89
            synonymMapping = getSynonymMapping();
90
            synonymMapping.initialize(state);
91

    
92
			//Export taxon relations
93
			success &= doPhase01(state, mapping);
94

    
95
			// Export name relations
96
			success &= doPhase02(state, mapping);
97

    
98
	         // Export synonym relations (directly attached to taxa)
99
            success &= doPhase03(state, synonymMapping);
100

    
101
			if (! success){
102
				state.getResult().addError("An unknown error occurred in PesiRelTaxonExport");
103
			}
104
		} catch (Exception e) {
105
			e.printStackTrace();
106
			logger.error(e.getMessage());
107
			state.getResult().addException(e);
108
			return;
109
		}
110
	}
111

    
112
    private boolean doPhase03(PesiExportState state, PesiExportMapping synonymMapping) {
113
        logger.info("PHASE 3: Direct Synonym Relationships ...");
114

    
115
        boolean success = true;
116
        int limit = state.getConfig().getLimitSave();
117
        // Start transaction
118
        TransactionStatus txStatus = startTransaction(true);
119
        logger.info("Started new transaction. Fetching some synonyms (max: " + limit + ") ...");
120

    
121
        List<Synonym> list;
122

    
123
        //taxon relations
124
        int partitionCount = 0;
125
        int totalCount = 0;
126
        while ((list = getNextTaxonPartition(Synonym.class, limit, partitionCount++, null))!= null) {
127
            totalCount = totalCount + list.size();
128
            logger.info("Read " + list.size() + " PESI synonyms. Limit: " + limit + ". Total: " + totalCount );
129
//          if (list.size() > 0){
130
//              logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
131
//          }
132
            for (Synonym synonym : list){
133
                try {
134
                    synonymMapping.invoke(synonym);
135
                } catch (Exception e) {
136
                    logger.error(e.getMessage() + ". Synonym: " +  synonym.getUuid());
137
                    e.printStackTrace();
138
                }
139
            }
140

    
141
            commitTransaction(txStatus);
142
            txStatus = startTransaction();
143
        }
144
        commitTransaction(txStatus);
145
        return success;
146
    }
147

    
148
    private boolean doPhase01(PesiExportState state, PesiExportMapping mapping) {
149
		logger.info("PHASE 1: Taxon Relationships ...");
150
		boolean success = true;
151

    
152
		int limit = state.getConfig().getLimitSave();
153
		// Start transaction
154
		TransactionStatus txStatus = startTransaction(true);
155
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
156

    
157
		List<RelationshipBase> list;
158

    
159
		//taxon relations
160
		int partitionCount = 0;
161
		int totalCount = 0;
162
		while ((list = getNextTaxonRelationshipPartition(limit, partitionCount++, null)) != null) {
163
			totalCount = totalCount + list.size();
164
			logger.info("Read " + list.size() + " PESI relations. Limit: " + limit + ". Total: " + totalCount );
165
//			if (list.size() > 0){
166
//				logger.warn("First relation type is " + list.get(0).getType().getTitleCache());
167
//			}
168
			for (RelationshipBase<?,?,?> rel : list){
169
				try {
170
					mapping.invoke(rel);
171
				} catch (Exception e) {
172
					logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
173
					e.printStackTrace();
174
				}
175
			}
176

    
177
			commitTransaction(txStatus);
178
			txStatus = startTransaction();
179
		}
180
		commitTransaction(txStatus);
181
		return success;
182
	}
183

    
184
	private boolean doPhase02(PesiExportState state, PesiExportMapping mapping2) {
185
		logger.info("PHASE 2: Name Relationships ...");
186
		boolean success = true;
187

    
188
		int limit = state.getConfig().getLimitSave();
189
		// Start transaction
190
		TransactionStatus txStatus = startTransaction(true);
191
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + limit + ") ...");
192

    
193
		//name relations
194
		List<NameRelationship> list;
195
		int partitionCount = 0;
196
		while ((list = getNextNameRelationshipPartition(NameRelationship.class, limit, partitionCount++, null)) != null   ) {
197
			txStatus = handleNameRelationList(state, txStatus, list);
198
		}
199
        //hybrid relations
200
		List<HybridRelationship> hybridList;
201
		partitionCount = 0;
202
        while ((hybridList = getNextNameRelationshipPartition(HybridRelationship.class, limit, partitionCount++, null)) != null   ) {
203
            txStatus = handleNameRelationList(state, txStatus, hybridList);
204
        }
205
        commitTransaction(txStatus);
206
		logger.info("End PHASE 2: Name Relationships ...");
207
		state.setCurrentFromObject(null);
208
		state.setCurrentToObject(null);
209
		return success;
210
	}
211

    
212
    private TransactionStatus handleNameRelationList(PesiExportState state, TransactionStatus txStatus,
213
            List<? extends RelationshipBase<?,?,?>> list) {
214
        for (RelationshipBase<?,?,?> rel : list){
215
        	try {
216
        	    TaxonName name1;
217
        	    TaxonName name2;
218
        		if (rel.isInstanceOf(HybridRelationship.class)){
219
        			HybridRelationship hybridRel = CdmBase.deproxy(rel, HybridRelationship.class);
220
        			name1 = hybridRel.getParentName();
221
        			name2 = hybridRel.getHybridName();
222
        		}else if (rel.isInstanceOf(NameRelationship.class)){
223
        			NameRelationship nameRel = CdmBase.deproxy(rel, NameRelationship.class);
224
        			name1 = nameRel.getFromName();
225
        			name2 = nameRel.getToName();
226
        		}else{
227
        			logger.warn ("Only hybrid- and name-relationships allowed here");
228
        			continue;
229
        		}
230
        		List<IdentifiableEntity> fromList = new ArrayList<>();
231
        		List<IdentifiableEntity> toList = new ArrayList<>();
232
        		makeList(name1, fromList);
233
        		makeList(name2, toList);
234

    
235
        		for (IdentifiableEntity<?> fromEntity : fromList){
236
        			for (IdentifiableEntity<?> toEntity : toList){
237
        				//TODO set entities to state
238
        				state.setCurrentFromObject(fromEntity);
239
        				state.setCurrentToObject(toEntity);
240
        				mapping.invoke(rel);
241
        			}
242
        		}
243
        		fromList = null;
244
        		toList = null;
245

    
246
        	} catch (Exception e) {
247
        		logger.error(e.getMessage() + ". Relationship: " +  rel.getUuid());
248
        		e.printStackTrace();
249
        	}
250
        }
251
        commitTransaction(txStatus);
252
        txStatus = startTransaction();
253
        return txStatus;
254
    }
255

    
256
	private void makeList(TaxonName name, List<IdentifiableEntity> list) {
257
		if (! hasPesiTaxon(name)){
258
			list.add(name);
259
		}else{
260
			for (TaxonBase<?> taxon:  getPesiTaxa(name)){
261
				list.add(taxon);
262
			}
263
		}
264
	}
265

    
266
	/**
267
	 * Deletes all entries of database tables related to <code>RelTaxon</code>.
268
	 * @param state The {@link PesiExportState PesiExportState}.
269
	 * @return Whether the delete operation was successful or not.
270
	 */
271
	protected boolean doDelete(PesiExportState state) {
272
		PesiExportConfigurator pesiConfig = state.getConfig();
273

    
274
		Source destination =  pesiConfig.getDestination();
275

    
276
		// Clear RelTaxon
277
		String sql = "DELETE FROM " + dbTableName;
278
		destination.update(sql);
279
		return true;
280
	}
281

    
282
	/**
283
	 * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
284
	 * @param relationship The {@link RelationshipBase Relationship}.
285
	 * @param state The {@link PesiExportState PesiExportState}.
286
	 * @return The <code>TaxonFk1</code> attribute.
287
	 * @see MethodMapper
288
	 */
289
    @SuppressWarnings("unused")
290
	private static Integer getTaxonFk1(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
291
		return getObjectFk(relationship, state, true);
292
	}
293

    
294
	/**
295
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>TaxonRelationship</code>.
296
     * @param relationship The {@link RelationshipBase Relationship}.
297
     * @param state The {@link PesiExportState PesiExportState}.
298
     * @return The <code>TaxonFk1</code> attribute.
299
     * @see MethodMapper
300
     */
301
    @SuppressWarnings("unused")
302
    private static Integer getTaxonFk1(Synonym synonym, PesiExportState state) {
303
        return synonym.getAcceptedTaxon().getId();
304
    }
305
    /**
306
     * Returns the <code>TaxonFk1</code> attribute. It corresponds to a CDM <code>Synonym</code>.
307
     * @param synonym The {@link Synonym synonym}.
308
     * @param state The {@link PesiExportState PesiExportState}.
309
     * @return The <code>TaxonFk1</code> attribute.
310
     * @see MethodMapper
311
     */
312
    @SuppressWarnings("unused")
313
    private static Integer getSynonym(Synonym synonym, PesiExportState state) {
314
        return state.getDbId(synonym);
315
    }
316

    
317
	/**
318
	 * Returns the <code>TaxonFk2</code> attribute. It corresponds to a CDM <code>SynonymRelationship</code>.
319
	 * @param relationship The {@link RelationshipBase Relationship}.
320
	 * @param state The {@link PesiExportState PesiExportState}.
321
	 * @return The <code>TaxonFk2</code> attribute.
322
	 * @see MethodMapper
323
	 */
324
    @SuppressWarnings("unused")
325
	private static Integer getTaxonFk2(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
326
		return getObjectFk(relationship, state, false);
327
	}
328

    
329
	/**
330
	 * Returns the <code>RelTaxonQualifierFk</code> attribute.
331
	 * @param relationship The {@link RelationshipBase Relationship}.
332
	 * @return The <code>RelTaxonQualifierFk</code> attribute.
333
	 * @see MethodMapper
334
	 */
335
	@SuppressWarnings("unused")
336
	private static Integer getRelTaxonQualifierFk(RelationshipBase<?, ?, ?> relationship) {
337
		return PesiTransformer.taxonRelation2RelTaxonQualifierFk(relationship);
338
	}
339

    
340
    @SuppressWarnings("unused")
341
    private static Integer getRelTaxonQualifierFk(Synonym synonym) {
342
        return PesiTransformer.synonym2RelTaxonQualifierFk(synonym);
343
    }
344

    
345
	/**
346
	 * Returns the <code>RelQualifierCache</code> attribute.
347
	 * @param relationship The {@link RelationshipBase Relationship}.
348
	 * @return The <code>RelQualifierCache</code> attribute.
349
	 * @see MethodMapper
350
	 */
351
	@SuppressWarnings("unused")
352
	private static String getRelQualifierCache(RelationshipBase<?, ?, ?> relationship, PesiExportState state) {
353
		String result = null;
354
		NomenclaturalCode code = null;
355
		Taxon taxon = null;
356
		TaxonName name= null;
357
		if (relationship.isInstanceOf(TaxonRelationship.class)){
358
			TaxonRelationship rel = CdmBase.deproxy(relationship, TaxonRelationship.class);
359
			taxon = rel.getToTaxon();
360
			name = taxon.getName();
361
			code = name.getNameType();
362
		}else if (relationship.isInstanceOf(NameRelationship.class)){
363
			NameRelationship rel = CdmBase.deproxy(relationship,  NameRelationship.class);
364
			name = rel.getFromName();
365
			code =name.getNameType();
366
		}else if (relationship.isInstanceOf(HybridRelationship.class)){
367
			HybridRelationship rel =  CdmBase.deproxy(relationship,  HybridRelationship.class);
368
			name = rel.getParentName();
369
			code = name.getNameType();
370
		}
371
		if (code != null) {
372
			result = state.getConfig().getTransformer().getCacheByRelationshipType(relationship, code);
373
		} else {
374
			logger.error("NomenclaturalCode is NULL while creating the following relationship: " + relationship.getUuid());
375
		}
376
		return result;
377
	}
378

    
379

    
380
	/**
381
	 * Returns the database key of an object in the given relationship.
382
	 * @param relationship {@link RelationshipBase RelationshipBase}.
383
	 * @param state {@link PesiExportState PesiExportState}.
384
	 * @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.
385
	 * @return The database key of an object in the given relationship.
386
	 */
387
	private static Integer getObjectFk(RelationshipBase<?, ?, ?> relationship, PesiExportState state, boolean isFrom) {
388
		TaxonBase<?> taxonBase = null;
389
		if (relationship.isInstanceOf(TaxonRelationship.class)) {
390
			TaxonRelationship tr = (TaxonRelationship)relationship;
391
			taxonBase = (isFrom) ? tr.getFromTaxon():  tr.getToTaxon();
392
		} else if (relationship.isInstanceOf(NameRelationship.class) ||  relationship.isInstanceOf(HybridRelationship.class)) {
393
			if (isFrom){
394
				return state.getDbId(state.getCurrentFromObject());
395
			}else{
396
				return state.getDbId(state.getCurrentToObject());
397
			}
398
		}
399
		if (taxonBase != null) {
400
			if (! isPesiTaxon(taxonBase)){
401
				logger.warn("Related taxonBase is not a PESI taxon. Taxon: " + taxonBase.getId() + "/" + taxonBase.getUuid() + "; TaxonRel: " +  relationship.getId() + "(" + relationship.getType().getTitleCache() + ")");
402
				return null;
403
			}else{
404
				return state.getDbId(taxonBase);
405
			}
406

    
407
		}
408
		logger.warn("No taxon found in state for relationship: " + relationship.toString());
409
		return null;
410
	}
411

    
412
    @SuppressWarnings("unused")  //for synonym mapping
413
    private static String getSynonymTypeCache(Synonym synonym, PesiExportState state) {
414
        String result = null;
415
        NomenclaturalCode code = null;
416
        code = synonym.getAcceptedTaxon().getName().getNameType();
417

    
418
        if (code != null) {
419
            result = state.getConfig().getTransformer().getCacheBySynonymType(synonym, code);
420
        } else {
421
            logger.error("NomenclaturalCode is NULL while creating the following synonym: " + synonym.getUuid());
422
        }
423
        return result;
424
    }
425

    
426
	/**
427
	 * Returns the CDM to PESI specific export mappings.
428
	 * @return The {@link PesiExportMapping PesiExportMapping}.
429
	 */
430
	PesiExportMapping getMapping() {
431
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
432

    
433
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getTaxonFk1", standardMethodParameter, PesiExportState.class));
434
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk2", this.getClass(), "getTaxonFk2", standardMethodParameter, PesiExportState.class));
435
		mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this));
436
		mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this, RelationshipBase.class, PesiExportState.class));
437
		mapping.addMapper(DbAnnotationMapper.NewInstance(getLastActionAnnotationTypes(), "Notes"));
438

    
439
		return mapping;
440
	}
441

    
442
	   /**
443
     * Returns the CDM to PESI specific export mappings.
444
     * @return The {@link PesiExportMapping PesiExportMapping}.
445
     */
446
    PesiExportMapping getSynonymMapping() {
447
        PesiExportMapping mapping = new PesiExportMapping(dbTableName);
448

    
449
        mapping.addMapper(MethodMapper.NewInstance("TaxonFk1", this.getClass(), "getSynonym", Synonym.class, PesiExportState.class));
450
        mapping.addMapper(DbObjectMapper.NewInstance("acceptedTaxon", "TaxonFk2"));
451
        mapping.addMapper(MethodMapper.NewInstance("RelTaxonQualifierFk", this, Synonym.class));
452
        mapping.addMapper(MethodMapper.NewInstance("RelQualifierCache", this.getClass(), "getSynonymTypeCache", Synonym.class, PesiExportState.class));
453
        mapping.addMapper(DbAnnotationMapper.NewInstance(getLastActionAnnotationTypes(), "Notes"));
454

    
455
        return mapping;
456
    }
457

    
458

    
459
    @Override
460
    protected boolean doCheck(PesiExportState state) {
461
        return true;
462
    }
463

    
464
    @Override
465
    protected boolean isIgnore(PesiExportState state) {
466
        return ! state.getConfig().isDoRelTaxa();
467
    }
468
}
(10-10/13)