Project

General

Profile

Download (17.4 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.old;
11

    
12
import java.sql.Connection;
13
import java.sql.PreparedStatement;
14
import java.sql.SQLException;
15
import java.util.HashMap;
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.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.UndefinedTransformerMethodException;
26
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
27
import eu.etaxonomy.cdm.io.pesi.out.PesiExportBase;
28
import eu.etaxonomy.cdm.io.pesi.out.PesiExportConfigurator;
29
import eu.etaxonomy.cdm.io.pesi.out.PesiExportMapping;
30
import eu.etaxonomy.cdm.io.pesi.out.PesiExportState;
31
import eu.etaxonomy.cdm.io.pesi.out.PesiTransformer;
32
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
35
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
36
import eu.etaxonomy.cdm.model.description.Distribution;
37
import eu.etaxonomy.cdm.model.description.TaxonDescription;
38
import eu.etaxonomy.cdm.model.location.NamedArea;
39
import eu.etaxonomy.cdm.model.reference.Reference;
40
import eu.etaxonomy.cdm.model.taxon.Taxon;
41
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
42
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
43

    
44
/**
45
 * The export class for {@link eu.etaxonomy.cdm.model.description.Distribution Distributions}.<p>
46
 * Inserts into DataWarehouse database table <code>Occurrence</code>.
47
 * @author e.-m.lee
48
 * @date 02.03.2010
49
 *
50
 */
51
@Component
52
public class PesiOccurrenceExport extends PesiExportBase {
53
	private static final Logger logger = Logger.getLogger(PesiOccurrenceExport.class);
54
	private static final Class<? extends CdmBase> standardMethodParameter = AnnotatableEntity.class;
55

    
56
	private static int modCount = 1000;
57
	private static final String dbTableName = "Occurrence";
58
	private static final String pluralString = "Occurrences";
59
	private static final String parentPluralString = "Taxa";
60
	private static Taxon taxon = null;
61
	private static Map<Integer, Integer> sourceId2OccurenceIdMap = new HashMap<Integer, Integer>();
62
	private static NamedArea namedArea = null;
63
	private static Distribution distribution = null;
64

    
65
	public PesiOccurrenceExport() {
66
		super();
67
	}
68

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

    
77
	/* (non-Javadoc)
78
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
79
	 */
80
	@Override
81
	protected boolean doCheck(PesiExportState state) {
82
		boolean result = true;
83
		return result;
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.error("*** Started Making " + pluralString + " ...");
93
	
94
			// Get the limit for objects to save within a single transaction.
95
			int limit = state.getConfig().getLimitSave();
96

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

    
100
			// PESI: Clear the database table Occurrence.
101
//			doDelete(state);
102
	
103
			// Get specific mappings: (CDM) Occurrence -> (PESI) Occurrence
104
			PesiExportMapping mapping = getMapping();
105

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

    
109
			// PESI: Create the Occurrences
110
			int count = 0;
111
			int taxonCount = 0;
112
			int pastCount = 0;
113
			TransactionStatus txStatus = null;
114
			List<TaxonBase> list = null;
115

    
116
			// Start transaction
117
			txStatus = startTransaction(true);
118
			logger.error("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
119
			while ((list = getTaxonService().list(null, limit, taxonCount, null, null)).size() > 0) {
120

    
121
				taxonCount += list.size();
122
				logger.error("Fetched " + list.size() + " " + parentPluralString + ".");
123
				for (TaxonBase taxonBase : list) {
124
					if (taxonBase.isInstanceOf(Taxon.class)) {
125
						
126
						// Set the current Taxon
127
						taxon = CdmBase.deproxy(taxonBase, Taxon.class);
128

    
129
						// Determine the TaxonDescriptions
130
						Set<TaxonDescription> taxonDescriptions = taxon.getDescriptions();
131

    
132
						// Determine the DescriptionElements (Citations) for the current Taxon
133
						for (TaxonDescription taxonDescription : taxonDescriptions) {
134
							Set<DescriptionElementBase> descriptionElements = taxonDescription.getElements();
135
							for (DescriptionElementBase descriptionElement : descriptionElements) {
136
								Set<DescriptionElementSource> elementSources = descriptionElement.getSources();
137
								
138
								if (descriptionElement.isInstanceOf(Distribution.class)) {
139
									Distribution distribution = CdmBase.deproxy(descriptionElement, Distribution.class);
140
									setNamedArea(distribution.getArea());
141
									setDistribution(distribution);
142

    
143
									// Differentiate between descriptionElements with and without sources.
144
									if (elementSources.size() == 0 && state.getDbId(descriptionElement) != null) {
145
										if (neededValuesNotNull(descriptionElement, state)) {
146
											doCount(count++, modCount, pluralString);
147
											success &= mapping.invoke(descriptionElement);
148
										}
149
									} else {
150
										for (DescriptionElementSource elementSource : elementSources) {
151
											Reference reference = elementSource.getCitation();
152
	
153
											// Citations can be empty (null): Is it wrong data or just a normal case?
154
											if (reference != null && state.getDbId(reference) != null) {
155
												if (neededValuesNotNull(reference, state)) {
156
													doCount(count++, modCount, pluralString);
157
													success &= mapping.invoke(reference);
158
												}
159
											}
160
										}
161
										
162
									}
163
									
164
									setDistribution(null);
165
								}
166
								
167
							}
168
						}
169
					}
170
				}
171
				
172
				// Commit transaction
173
				commitTransaction(txStatus);
174
				logger.error("Committed transaction.");
175
				logger.error("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
176
				pastCount = count;
177

    
178
				// Start transaction
179
				txStatus = startTransaction(true);
180
				logger.error("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
181
			}
182
			if (list.size() == 0) {
183
				logger.error("No " + parentPluralString + " left to fetch.");
184
			}
185
			list = null;
186
			// Commit transaction
187
			commitTransaction(txStatus);
188
			logger.error("Committed transaction.");
189

    
190
			logger.error("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
191
			
192
			if (!success){
193
				state.setUnsuccessfull();
194
			}
195
			return;
196
		} catch (SQLException e) {
197
			e.printStackTrace();
198
			logger.error(e.getMessage());
199
			state.setUnsuccessfull();
200
			return;
201
		}
202
	}
203

    
204
	/**
205
	 * Checks whether needed values for an entity are NULL.
206
	 * @return
207
	 */
208
	private boolean neededValuesNotNull(AnnotatableEntity entity, PesiExportState state) {
209
		boolean result = true;
210
		if (getTaxonFk(entity, state) == null) {
211
			logger.error("TaxonFk is NULL, but is not allowed to be. Therefore no record was written to export database for this entity: " + entity.getUuid());
212
			result = false;
213
		}
214
		if (getAreaFk(entity) == null) {
215
			logger.error("AreaFk is NULL, but is not allowed to be. Therefore no record was written to export database for this entity: " + entity.getUuid());
216
			result = false;
217
		}
218
		if (getOccurrenceStatusFk(entity) == null) {
219
			logger.error("OccurrenceStatusFk is NULL, but is not allowed to be. Therefore no record was written to export database for this entity: " + entity.getUuid());
220
			result = false;
221
		}
222
		return result;
223
	}
224

    
225
	/**
226
	 * Creates the entries for the database table 'OccurrenceSource'.
227
	 * @param entity
228
	 * @param state
229
	 * @return
230
	 */
231
	protected boolean invokeOccurrenceSource(AnnotatableEntity entity, PesiExportState state) {
232
		if (entity == null) {
233
			return true;
234
		} else {
235
			// Create OccurrenceSource database table entry
236
			String lastStoredRecordSql = "Insert Into OccurrenceSource (OccurrenceFk, SourceFk, SourceNameCache, OldTaxonName) " +
237
					"values(?, ?, ?, ?)";
238
			Connection con = state.getConfig().getDestination().getConnection();
239

    
240
			try {
241
				PreparedStatement stmt = con.prepareStatement(lastStoredRecordSql);
242
				Integer sourceFk = getSourceFk(entity, state);
243
				stmt.setInt(1, sourceId2OccurenceIdMap.get(sourceFk));
244
				stmt.setInt(2, sourceFk);
245
				stmt.setString(3, getSourceCache(entity));
246
				stmt.setString(4, null); // Which taxon are we talking about?
247
				stmt.executeUpdate();
248
				return true;
249
			} catch (SQLException e) {
250
				logger.error("SQLException during getOccurrenceId invoke...");
251
				e.printStackTrace();
252
				return false;
253
			}
254
		}
255
	}
256

    
257
	/**
258
	 * Deletes all entries of database tables related to <code>Occurrence</code>.
259
	 * @param state The {@link PesiExportState PesiExportState}.
260
	 * @return Whether the delete operation was successful or not.
261
	 */
262
	protected boolean doDelete(PesiExportState state) {
263
		PesiExportConfigurator pesiConfig = (PesiExportConfigurator) state.getConfig();
264
		
265
		String sql;
266
		Source destination =  pesiConfig.getDestination();
267

    
268
		// Clear Occurrence
269
		sql = "DELETE FROM " + dbTableName;
270
		destination.setQuery(sql);
271
		destination.update(sql);
272
		return true;
273
	}
274

    
275
	/* (non-Javadoc)
276
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
277
	 */
278
	@Override
279
	protected boolean isIgnore(PesiExportState state) {
280
		return ! state.getConfig().isDoOccurrence();
281
	}
282

    
283
	/**
284
	 * Returns the <code>TaxonFk</code> attribute.
285
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
286
	 * @param state The {@link PesiExportState PesiExportState}.
287
	 * @return The <code>TaxonFk</code> attribute.
288
	 * @see MethodMapper
289
	 */
290
	private static Integer getTaxonFk(AnnotatableEntity entity, PesiExportState state) {
291
		// AnnotatableEntity parameter isn't needed, but the DbSingleAttributeExportMapperBase throws a type mismatch exception otherwise
292
		// since it awaits two parameters if one of them is of instance DbExportStateBase.
293
		Integer result = null;
294
		if (state != null && taxon != null) {
295
			result = state.getDbId(taxon.getName());
296
		}
297
		return result;
298
	}
299

    
300
	/**
301
	 * Returns the <code>TaxonFullNameCache</code> attribute.
302
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
303
	 * @return The <code>TaxonFullNameCache</code> attribute.
304
	 * @see MethodMapper
305
	 */
306
	@SuppressWarnings("unused")
307
	private static String getTaxonFullNameCache(AnnotatableEntity entity) {
308
		String result = null;
309
		result = taxon.getName().getTitleCache();
310
		return result;
311
	}
312

    
313
	/**
314
	 * Returns the <code>AreaFk</code> attribute.
315
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
316
	 * @return The <code>AreaFk</code> attribute.
317
	 * @see MethodMapper
318
	 */
319
	private static Integer getAreaFk(AnnotatableEntity entity) {
320
		Integer result = null;
321
		if (getNamedArea() != null) {
322
			//TODO not working any more after transformer refactoring
323
			try {
324
				result = (Integer)new PesiTransformer(null).getKeyByNamedArea(namedArea);
325
			} catch (UndefinedTransformerMethodException e) {
326
				e.printStackTrace();
327
			}
328
		} else {
329
			logger.warn("This should never happen, but a NamedArea could not be found for entity: " + entity.getUuid());
330
		}
331
		return result;
332
	}
333

    
334
	/**
335
	 * Returns the <code>AreaNameCache</code> attribute.
336
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
337
	 * @return The <code>AreaNameCache</code> attribute.
338
	 * @see MethodMapper
339
	 */
340
	@SuppressWarnings("unused")
341
	private static String getAreaNameCache(AnnotatableEntity entity) {
342
		String result = null;
343
		if (getNamedArea() != null) {
344
			//TODO not working any more after transformer refactoring
345
			try {
346
				result = new PesiTransformer(null).getCacheByNamedArea(namedArea);
347
			} catch (UndefinedTransformerMethodException e) {
348
				e.printStackTrace();
349
			}
350
		} else {
351
			logger.warn("This should never happen, but a NamedArea could not be found for entity: " + entity.getUuid());
352
		}
353
		return result;
354
	}
355

    
356
	/**
357
	 * @return the distribution
358
	 */
359
	public static Distribution getDistribution() {
360
		return distribution;
361
	}
362

    
363
	/**
364
	 * @param distribution the distribution to set
365
	 */
366
	public static void setDistribution(Distribution distribution) {
367
		PesiOccurrenceExport.distribution = distribution;
368
	}
369

    
370
	/**
371
	 * @return the namedArea
372
	 */
373
	public static NamedArea getNamedArea() {
374
		return namedArea;
375
	}
376

    
377
	/**
378
	 * @param namedArea the namedArea to set
379
	 */
380
	public static void setNamedArea(NamedArea namedArea) {
381
		PesiOccurrenceExport.namedArea = namedArea;
382
	}
383

    
384
	/**
385
	 * Returns the <code>OccurrenceStatusFk</code> attribute.
386
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
387
	 * @return The <code>OccurrenceStatusFk</code> attribute.
388
	 * @throws UnknownCdmTypeException 
389
	 * @see MethodMapper
390
	 */
391
	private static Integer getOccurrenceStatusFk(AnnotatableEntity entity) {
392
		Integer result = null;
393
		if (getDistribution() != null) {
394
			result = PesiTransformer.presenceAbsenceTerm2OccurrenceStatusId(getDistribution().getStatus());
395
		}
396
		return result;
397
	}
398

    
399
	/**
400
	 * Returns the <code>OccurrenceStatusCache</code> attribute.
401
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
402
	 * @return The <code>OccurrenceStatusCache</code> attribute.
403
	 * @throws UndefinedTransformerMethodException 
404
	 * @throws UnknownCdmTypeException 
405
	 * @see MethodMapper
406
	 */
407
	@SuppressWarnings("unused")
408
	private static String getOccurrenceStatusCache(AnnotatableEntity entity, PesiExportState state) throws UndefinedTransformerMethodException {
409
		String result = null;
410
		if (getDistribution() != null) {
411
			result = state.getTransformer().getCacheByPresenceAbsenceTerm(getDistribution().getStatus());
412
		}
413
		return result;
414
	}
415

    
416
	/**
417
	 * Returns the <code>SourceFk</code> attribute.
418
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
419
	 * @param state The {@link PesiExportState PesiExportState}.
420
	 * @return The <code>SourceFk</code> attribute.
421
	 * @see MethodMapper
422
	 */
423
	private static Integer getSourceFk(AnnotatableEntity entity, PesiExportState state) {
424
		Integer result = null;
425
		if (state != null && entity != null && entity.isInstanceOf(Distribution.class)) {
426
			Distribution distribution = CdmBase.deproxy(entity, Distribution.class);
427
			Set<DescriptionElementSource> sources = distribution.getSources();
428
			if (sources.size() == 1) {
429
				DescriptionElementSource source = sources.iterator().next();
430
				result = state.getDbId(source.getCitation());
431
			} else if (sources.size() > 1) {
432
				logger.warn("Found Distribution with " + sources.size() + " sources.");
433
			}
434
		}
435
		return result;
436
	}
437

    
438
	/**
439
	 * Returns the <code>SourceCache</code> attribute.
440
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
441
	 * @return The <code>SourceCache</code> attribute.
442
	 * @see MethodMapper
443
	 */
444
	private static String getSourceCache(AnnotatableEntity entity) {
445
		String result = null;
446
		Reference reference;
447
		if (entity != null && entity.isInstanceOf(Distribution.class)) {
448
			Distribution distribution = CdmBase.deproxy(entity, Distribution.class);
449
			Set<DescriptionElementSource> sources = distribution.getSources();
450
			if (sources.size() == 1) {
451
				DescriptionElementSource source = sources.iterator().next();
452
				reference = source.getCitation();
453
				if (reference != null) {
454
					result = reference.getTitle();
455
				}
456
			} else if (sources.size() > 1) {
457
				logger.warn("Found Distribution with " + sources.size() + " sources.");
458
			}
459
		}
460
		return result;
461
	}
462

    
463
	/**
464
	 * Returns the <code>Notes</code> attribute.
465
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
466
	 * @return The <code>Notes</code> attribute.
467
	 * @see MethodMapper
468
	 */
469
	@SuppressWarnings("unused")
470
	private static String getNotes(AnnotatableEntity entity) {
471
		// TODO
472
		return null;
473
	}
474

    
475
	/**
476
	 * Returns the CDM to PESI specific export mappings.
477
	 * @return The {@link PesiExportMapping PesiExportMapping}.
478
	 */
479
	private PesiExportMapping getMapping() {
480
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
481
		
482
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this.getClass(), "getTaxonFk", standardMethodParameter, PesiExportState.class));
483
		mapping.addMapper(MethodMapper.NewInstance("AreaFk", this));
484
		mapping.addMapper(MethodMapper.NewInstance("TaxonFullNameCache", this));
485
		mapping.addMapper(MethodMapper.NewInstance("AreaNameCache", this));
486
		mapping.addMapper(MethodMapper.NewInstance("OccurrenceStatusFk", this));
487
		mapping.addMapper(MethodMapper.NewInstance("OccurrenceStatusCache", this, AnnotatableEntity.class, PesiExportState.class));
488
		mapping.addMapper(MethodMapper.NewInstance("SourceFk", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
489
		mapping.addMapper(MethodMapper.NewInstance("SourceCache", this));
490
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
491

    
492
		return mapping;
493
	}
494

    
495
}
(5-5/6)