Project

General

Profile

Download (20.3 KB) Statistics
| Branch: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2009 EDIT
4
* European Distributed Institute of Taxonomy 
5
* http://www.e-taxonomy.eu
6
* 
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.cdm.io.pesi.out;
11

    
12
import java.sql.Connection;
13
import java.sql.PreparedStatement;
14
import java.sql.SQLException;
15
import java.util.Arrays;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Set;
19

    
20
import org.apache.log4j.Logger;
21
import org.joda.time.DateTime;
22
import org.springframework.stereotype.Component;
23
import org.springframework.transaction.TransactionStatus;
24

    
25
import eu.etaxonomy.cdm.io.common.DbExportStateBase;
26
import eu.etaxonomy.cdm.io.common.Source;
27
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
28
import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
29
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
30
import eu.etaxonomy.cdm.model.common.CdmBase;
31
import eu.etaxonomy.cdm.model.common.Extension;
32
import eu.etaxonomy.cdm.model.common.ExtensionType;
33
import eu.etaxonomy.cdm.model.common.Language;
34
import eu.etaxonomy.cdm.model.common.LanguageString;
35
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
36
import eu.etaxonomy.cdm.model.description.DescriptionBase;
37
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38
import eu.etaxonomy.cdm.model.description.Distribution;
39
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
40
import eu.etaxonomy.cdm.model.description.TaxonDescription;
41
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
42
import eu.etaxonomy.cdm.model.description.TextData;
43
import eu.etaxonomy.cdm.model.location.NamedArea;
44
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
45
import eu.etaxonomy.cdm.model.taxon.Taxon;
46
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
47

    
48
/**
49
 * The export class for {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase DescriptionElements}.<p>
50
 * Inserts into DataWarehouse database table <code>Note</code>.<p>
51
 * It is divided into two phases:<ul>
52
 * <li>Phase 1:	Export of DescriptionElements as Notes.
53
 * <li>Phase 2:	Export of TaxonName extensions <code>taxComment</code>, <code>fauComment</code> and <code>fauExtraCodes</code> as Notes.</ul>
54
 * @author e.-m.lee
55
 * @date 23.02.2010
56
 *
57
 */
58
@Component
59
public class PesiNoteExport extends PesiExportBase {
60
	private static final Logger logger = Logger.getLogger(PesiNoteExport.class);
61
	private static final Class<? extends CdmBase> standardMethodParameter = DescriptionElementBase.class;
62

    
63
	private static int modCount = 1000;
64
	private static final String dbTableName = "Note";
65
	private static final String pluralString = "Notes";
66
	private static final String parentPluralString = "Taxa";
67

    
68
	public PesiNoteExport() {
69
		super();
70
	}
71

    
72
	/* (non-Javadoc)
73
	 * @see eu.etaxonomy.cdm.io.common.DbExportBase#getStandardMethodParameter()
74
	 */
75
	@Override
76
	public Class<? extends CdmBase> getStandardMethodParameter() {
77
		return standardMethodParameter;
78
	}
79

    
80
	/* (non-Javadoc)
81
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
82
	 */
83
	@Override
84
	protected boolean doCheck(PesiExportState state) {
85
		boolean result = true;
86
		return result;
87
	}
88

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

    
97
			// Get the limit for objects to save within a single transaction.
98
			int limit = state.getConfig().getLimitSave();
99
			
100
			// Stores whether this invoke was successful or not.
101
			boolean success = true;
102
	
103
			// PESI: Clear the database table Note.
104
			doDelete(state);
105
		
106
			// Start transaction
107
			success &= doPhase01(state);
108

    
109
			
110
			logger.info("PHASE 2...");
111
			doPhase02(state, limit);
112

    
113

    
114
			logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
115
			
116
			if (!success){
117
				state.setUnsuccessfull();
118
			}
119
			return;
120
		} catch (SQLException e) {
121
			e.printStackTrace();
122
			logger.error(e.getMessage());
123
			state.setUnsuccessfull();
124
		}
125
	}
126

    
127
	//PHASE 01: Description Elements
128
	private boolean doPhase01(PesiExportState state) throws SQLException {
129
		logger.info("PHASE 1...");
130
		int count = 0;
131
		int pastCount = 0;
132
		 boolean success = true;
133
		
134
		 // Calculate the pageNumber
135
		int pageNumber = 1;
136
		int pageSize = 1000;
137

    
138

    
139
		// Get specific mappings: (CDM) DescriptionElement -> (PESI) Note
140
		PesiExportMapping mapping = getMapping();
141

    
142
		// Initialize the db mapper
143
		mapping.initialize(state);
144

    
145
		
146
		List<DescriptionElementBase> list = null;
147
		
148
		TransactionStatus txStatus = startTransaction(true);
149
		logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + pageSize + ") ...");
150
		List<String> propPath = Arrays.asList(new String[]{"inDescription.taxon"});
151
		while ((list = getDescriptionService().listDescriptionElements(null, null, null, pageSize, pageNumber, propPath)).size() > 0) {
152

    
153
			logger.info("Fetched " + list.size() + " " + pluralString + ". Exporting...");
154
			for (DescriptionElementBase descriptionElement : list) {
155
				if (getNoteCategoryFk(descriptionElement) != null) {
156
					doCount(count++, modCount, pluralString);
157
					success &= mapping.invoke(descriptionElement);
158
				}
159
			}
160

    
161
			// Commit transaction
162
			commitTransaction(txStatus);
163
			logger.debug("Committed transaction.");
164
			logger.info("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
165
			pastCount = count;
166

    
167
			// Start transaction
168
			txStatus = startTransaction(true);
169
			logger.info("Started new transaction. Fetching some " + pluralString + " (max: " + pageSize + ") ...");
170
			
171
			// Increment pageNumber
172
			pageNumber++;
173
		}
174
		if (list.size() == 0) {
175
			logger.info("No " + pluralString + " left to fetch.");
176
		}
177
		// Commit transaction
178
		commitTransaction(txStatus);
179
		logger.info("Committed transaction.");
180
		return success;
181
	}
182

    
183
	//PHASE 02: Taxa extensions
184
	private void doPhase02(PesiExportState state, int limit) {
185
		TransactionStatus txStatus;
186
		txStatus = startTransaction(true);
187
		ExtensionType taxCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.taxCommentUuid);
188
		ExtensionType fauCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.fauCommentUuid);
189
		ExtensionType fauExtraCodesExtensionType = (ExtensionType)getTermService().find(PesiTransformer.fauExtraCodesUuid);
190
		List<TaxonBase> taxonBaseList = null;
191
		
192
		int count = 0;
193
		int pastCount = 0;
194
		Connection connection = state.getConfig().getDestination().getConnection();
195
		logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
196
		//logger.warn("TODO handle extensions on taxon level, not name level (");
197
		while ((taxonBaseList = getTaxonService().list(null, limit, count, null, null)).size() > 0) {
198

    
199
			logger.info("Fetched " + taxonBaseList.size() + " names. Exporting...");
200
			for (TaxonBase<?> taxon : taxonBaseList) {
201
				Set<Extension> extensions = taxon.getExtensions();
202
				for (Extension extension : extensions) {
203
					if (extension.getType().equals(taxCommentExtensionType)) {
204
						String taxComment = extension.getValue();
205
						invokeNotes(taxComment, 
206
								PesiTransformer.getNoteCategoryFk(PesiTransformer.taxCommentUuid), 
207
								PesiTransformer.getNoteCategoryCache(PesiTransformer.taxCommentUuid),
208
								null, null, getTaxonFk(taxon.getName(), state),connection);
209
					} else if (extension.getType().equals(fauCommentExtensionType)) {
210
						String fauComment = extension.getValue();
211
						invokeNotes(fauComment, 
212
								PesiTransformer.getNoteCategoryFk(PesiTransformer.fauCommentUuid), 
213
								PesiTransformer.getNoteCategoryCache(PesiTransformer.fauCommentUuid),
214
								null, null, getTaxonFk(taxon.getName(), state),connection);
215
					} else if (extension.getType().equals(fauExtraCodesExtensionType)) {
216
						String fauExtraCodes = extension.getValue();
217
						invokeNotes(fauExtraCodes, 
218
								PesiTransformer.getNoteCategoryFk(PesiTransformer.fauExtraCodesUuid), 
219
								PesiTransformer.getNoteCategoryCache(PesiTransformer.fauExtraCodesUuid),
220
								null, null, getTaxonFk(taxon.getName(), state),connection);
221
					}
222
				}
223
				
224
				doCount(count++, modCount, pluralString);
225
			}
226

    
227
			// Commit transaction
228
			commitTransaction(txStatus);
229
			logger.debug("Committed transaction.");
230
			logger.info("Exported " + (count - pastCount) + " names. Total: " + count);
231
			pastCount = count;
232

    
233
			// Start transaction
234
			txStatus = startTransaction(true);
235
			logger.info("Started new transaction. Fetching some taxa first (max: " + limit + ") ...");
236
		}
237
		if (taxonBaseList.size() == 0) {
238
			logger.info("No taxa left to fetch.");
239
		}
240
		// Commit transaction
241
		commitTransaction(txStatus);
242
		logger.debug("Committed transaction.");
243
	}
244

    
245
	/**
246
	 * @param taxComment
247
	 * @param noteCategoryFk
248
	 * @param noteCategoryCache
249
	 * @param object
250
	 * @param object2
251
	 */
252
	private void invokeNotes(String note, Integer noteCategoryFk,
253
			String noteCategoryCache, Integer languageFk, String languageCache, 
254
			Integer taxonFk, Connection connection) {
255
		String notesSql = "UPDATE Note SET Note_1 = ?, NoteCategoryFk = ?, NoteCategoryCache = ?, LanguageFk = ?, LanguageCache = ? WHERE TaxonFk = ?"; 
256
		try {
257
			PreparedStatement notesStmt = connection.prepareStatement(notesSql);
258
			
259
			if (note != null) {
260
				notesStmt.setString(1, note);
261
			} else {
262
				notesStmt.setObject(1, null);
263
			}
264
			
265
			if (noteCategoryFk != null) {
266
				notesStmt.setInt(2, noteCategoryFk);
267
			} else {
268
				notesStmt.setObject(2, null);
269
			}
270
			
271
			if (noteCategoryCache != null) {
272
				notesStmt.setString(3, noteCategoryCache);
273
			} else {
274
				notesStmt.setObject(3, null);
275
			}
276
			
277
			if (languageFk != null) {
278
				notesStmt.setInt(4, languageFk);
279
			} else {
280
				notesStmt.setObject(4, null);
281
			}
282
			
283
			if (languageCache != null) {
284
				notesStmt.setString(5, languageCache);
285
			} else {
286
				notesStmt.setObject(5, null);
287
			}
288
			
289
			if (taxonFk != null) {
290
				notesStmt.setInt(6, taxonFk);
291
			} else {
292
				notesStmt.setObject(6, null);
293
			}
294
			
295
			notesStmt.executeUpdate();
296
		} catch (SQLException e) {
297
			logger.error("Note could not be created: " + note);
298
			e.printStackTrace();
299
		}
300

    
301

    
302
	}
303

    
304
	/**
305
	 * Deletes all entries of database tables related to <code>Note</code>.
306
	 * @param state The PesiExportState
307
	 * @return Whether the delete operation was successful or not.
308
	 */
309
	protected boolean doDelete(PesiExportState state) {
310
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
311
		
312
		String sql;
313
		Source destination =  pesiConfig.getDestination();
314

    
315
		// Clear NoteSource
316
		sql = "DELETE FROM NoteSource";
317
		destination.setQuery(sql);
318
		destination.update(sql);
319

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

    
327
	/* (non-Javadoc)
328
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
329
	 */
330
	@Override
331
	protected boolean isIgnore(PesiExportState state) {
332
		return ! state.getConfig().isDoNotes();
333
	}
334

    
335
	/**
336
	 * Returns the <code>Note_1</code> attribute.
337
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
338
	 * @return The <code>Note_1</code> attribute.
339
	 * @see MethodMapper
340
	 */
341
	@SuppressWarnings("unused")
342
	private static String getNote_1(DescriptionElementBase descriptionElement) {
343
		String result = null;
344

    
345
		if (descriptionElement.isInstanceOf(TextData.class)) {
346
			TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
347
			result = textData.getText(Language.DEFAULT());
348
		}
349

    
350
		return result;
351
	}
352

    
353
	/**
354
	 * Returns the <code>Note_2</code> attribute.
355
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
356
	 * @return The <code>Note_2</code> attribute.
357
	 * @see MethodMapper
358
	 */
359
	@SuppressWarnings("unused")
360
	private static String getNote_2(DescriptionElementBase descriptionElement) {
361
		logger.warn("Not yet implemented");
362
		return null;
363
	}
364

    
365
	/**
366
	 * Returns the <code>NoteCategoryFk</code> attribute.
367
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
368
	 * @return The <code>NoteCategoryFk</code> attribute.
369
	 * @see MethodMapper
370
	 */
371
	private static Integer getNoteCategoryFk(DescriptionElementBase descriptionElement) {
372
		Integer result = null;
373
		result = PesiTransformer.feature2NodeCategoryFk(descriptionElement.getFeature());
374
		return result;
375
	}
376
	
377
	/**
378
	 * Returns the <code>NoteCategoryCache</code> attribute.
379
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
380
	 * @return The <code>NoteCategoryCache</code> attribute.
381
	 * @see MethodMapper
382
	 */
383
	@SuppressWarnings("unused")
384
	private static String getNoteCategoryCache(DescriptionElementBase descriptionElement) {
385
		String result = null;
386

    
387
		if (descriptionElement.isInstanceOf(TextData.class)) {
388
			result = PesiTransformer.textData2NodeCategoryCache(descriptionElement.getFeature());
389
		}
390

    
391
		return result;
392
	}
393

    
394
	/**
395
	 * Returns the <code>LanguageFk</code> attribute.
396
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
397
	 * @return The <code>LanguageFk</code> attribute.
398
	 * @see MethodMapper
399
	 */
400
	@SuppressWarnings("unused")
401
	private static Integer getLanguageFk(DescriptionElementBase descriptionElement) {
402
		Language language = getLanguage(descriptionElement);
403

    
404
		return PesiTransformer.language2LanguageId(language);
405
	}
406

    
407
	/**
408
	 * Returns the <code>LanguageCache</code> attribute.
409
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
410
	 * @return The <code>LanguageCache</code> attribute.
411
	 * @see MethodMapper
412
	 */
413
	@SuppressWarnings("unused")
414
	private static String getLanguageCache(DescriptionElementBase descriptionElement) {
415
		Language language = getLanguage(descriptionElement);
416

    
417
		return PesiTransformer.language2LanguageCache(language);
418
	}
419

    
420
	private static Language getLanguage(DescriptionElementBase descriptionElement) {
421
		Language language = null;
422

    
423
		Map<Language, LanguageString> multilanguageText = null;
424
		if (descriptionElement.isInstanceOf(CommonTaxonName.class)) {
425
			CommonTaxonName commonTaxonName = CdmBase.deproxy(descriptionElement, CommonTaxonName.class);
426
			language = commonTaxonName.getLanguage();
427
		} else if (descriptionElement.isInstanceOf(TextData.class)) {
428
			TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
429
			multilanguageText = textData.getMultilanguageText();
430
		} else if (descriptionElement.isInstanceOf(IndividualsAssociation.class)) {
431
			IndividualsAssociation individualsAssociation = CdmBase.deproxy(descriptionElement, IndividualsAssociation.class);
432
			multilanguageText = individualsAssociation.getDescription();
433
		} else if (descriptionElement.isInstanceOf(TaxonInteraction.class)) {
434
			TaxonInteraction taxonInteraction = CdmBase.deproxy(descriptionElement, TaxonInteraction.class);
435
			multilanguageText = taxonInteraction.getDescriptions();
436
		} else {
437
			logger.debug("Given descriptionElement does not support languages. Hence LanguageCache could not be determined: " + descriptionElement.getUuid());
438
		}
439
		
440
		if (multilanguageText != null) {
441
			Set<Language> languages = multilanguageText.keySet();
442

    
443
			// TODO: Think of something more sophisticated than this
444
			if (languages.size() > 0) {
445
				language = languages.iterator().next();
446
			}
447
			if (languages.size() > 1){
448
				logger.warn("There is more than 1 language for a given description (" + descriptionElement.getClass().getSimpleName() + "):" + descriptionElement.getUuid());
449
			}
450
		}
451
		return language;
452
	}
453

    
454
	/**
455
	 * Returns the <code>Region</code> attribute.
456
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
457
	 * @return The <code>Region</code> attribute.
458
	 * @see MethodMapper
459
	 */
460
	@SuppressWarnings("unused")
461
	private static String getRegion(DescriptionElementBase descriptionElement) {
462
		String result = null;
463
		DescriptionBase<?> inDescription = descriptionElement.getInDescription();
464
		
465
		try {
466
			// Area information are associated to TaxonDescriptions and Distributions.
467
			if (descriptionElement.isInstanceOf(Distribution.class)) {
468
				Distribution distribution = CdmBase.deproxy(descriptionElement, Distribution.class);
469
				//TODO not working any more after transformer refactoring
470
				result = new PesiTransformer(null).getCacheByNamedArea(distribution.getArea());
471
			} else if (inDescription != null && inDescription.isInstanceOf(TaxonDescription.class)) {
472
				TaxonDescription taxonDescription = CdmBase.deproxy(inDescription, TaxonDescription.class);
473
				Set<NamedArea> namedAreas = taxonDescription.getGeoScopes();
474
				if (namedAreas.size() == 1) {
475
					result = new PesiTransformer(null).getCacheByNamedArea(namedAreas.iterator().next());
476
				} else if (namedAreas.size() > 1) {
477
					logger.warn("This TaxonDescription contains more than one NamedArea: " + taxonDescription.getTitleCache());
478
				}
479
			}
480
		} catch (ClassCastException e) {
481
			// TODO Auto-generated catch block
482
			e.printStackTrace();
483
		} catch (UndefinedTransformerMethodException e) {
484
			// TODO Auto-generated catch block
485
			e.printStackTrace();
486
		}
487
		return result;
488
	}
489

    
490
	/**
491
	 * Returns the <code>TaxonFk</code> attribute.
492
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
493
	 * @param state The {@link PesiExportState PesiExportState}.
494
	 * @return The <code>TaxonFk</code> attribute.
495
	 * @see MethodMapper
496
	 */
497
	@SuppressWarnings("unused")
498
	private static Integer getTaxonFk(DescriptionElementBase descriptionElement, DbExportStateBase<?> state) {
499
		Integer result = null;
500
		DescriptionBase<?> inDescription = descriptionElement.getInDescription();
501
		if (inDescription != null && inDescription.isInstanceOf(TaxonDescription.class)) {
502
			TaxonDescription taxonDescription = CdmBase.deproxy(inDescription, TaxonDescription.class);
503
			Taxon taxon = taxonDescription.getTaxon();
504
			result = state.getDbId(taxon.getName());
505
		}
506
		return result;
507
	}
508
	
509
	/**
510
	 * Returns the TaxonFk for a given TaxonName.
511
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
512
	 * @param state The {@link DbExportStateBase DbExportState}.
513
	 * @return
514
	 */
515
	private static Integer getTaxonFk(TaxonNameBase<?,?> taxonName, DbExportStateBase<?> state) {
516
		return state.getDbId(taxonName);
517
	}
518
	
519
	/**
520
	 * Returns the <code>LastAction</code> attribute.
521
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
522
	 * @return The <code>LastAction</code> attribute.
523
	 * @see MethodMapper
524
	 */
525
	@SuppressWarnings("unused")
526
	private static String getLastAction(DescriptionElementBase descriptionElement) {
527
		// TODO
528
		return null;
529
	}
530

    
531
	/**
532
	 * Returns the <code>LastActionDate</code> attribute.
533
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
534
	 * @return The <code>LastActionDate</code> attribute.
535
	 * @see MethodMapper
536
	 */
537
	@SuppressWarnings("unused")
538
	private static DateTime getLastActionDate(DescriptionElementBase descriptionElement) {
539
		DateTime result = null;
540
		return result;
541
	}
542

    
543
	/**
544
	 * Returns the CDM to PESI specific export mappings.
545
	 * @return The {@link PesiExportMapping PesiExportMapping}.
546
	 */
547
	private PesiExportMapping getMapping() {
548
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
549
		
550
		mapping.addMapper(IdMapper.NewInstance("NoteId"));
551
		mapping.addMapper(MethodMapper.NewInstance("Note_1", this));
552
		mapping.addMapper(MethodMapper.NewInstance("Note_2", this));
553
		mapping.addMapper(MethodMapper.NewInstance("NoteCategoryFk", this));
554
		mapping.addMapper(MethodMapper.NewInstance("NoteCategoryCache", this));
555
		mapping.addMapper(MethodMapper.NewInstance("LanguageFk", this));
556
		mapping.addMapper(MethodMapper.NewInstance("LanguageCache", this));
557
		mapping.addMapper(MethodMapper.NewInstance("Region", this));
558
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this.getClass(), "getTaxonFk", standardMethodParameter, DbExportStateBase.class));
559
		mapping.addMapper(MethodMapper.NewInstance("LastAction", this));
560
		mapping.addMapper(MethodMapper.NewInstance("LastActionDate", this));
561

    
562
		return mapping;
563
	}
564

    
565
}
(10-10/17)