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.old;
10

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

    
19
import org.apache.log4j.Logger;
20
import org.springframework.stereotype.Component;
21
import org.springframework.transaction.TransactionStatus;
22

    
23
import eu.etaxonomy.cdm.io.common.Source;
24
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
25
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
26
import eu.etaxonomy.cdm.io.pesi.out.PesiExportBase;
27
import eu.etaxonomy.cdm.io.pesi.out.PesiExportConfigurator;
28
import eu.etaxonomy.cdm.io.pesi.out.PesiExportMapping;
29
import eu.etaxonomy.cdm.io.pesi.out.PesiExportState;
30
import eu.etaxonomy.cdm.io.pesi.out.PesiTransformer;
31
import eu.etaxonomy.cdm.model.common.AnnotatableEntity;
32
import eu.etaxonomy.cdm.model.common.CdmBase;
33
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
34
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
35
import eu.etaxonomy.cdm.model.description.Distribution;
36
import eu.etaxonomy.cdm.model.description.TaxonDescription;
37
import eu.etaxonomy.cdm.model.location.NamedArea;
38
import eu.etaxonomy.cdm.model.reference.Reference;
39
import eu.etaxonomy.cdm.model.taxon.Taxon;
40
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
41
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
42

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

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

    
64
	public PesiOccurrenceExport() {
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
	/* (non-Javadoc)
86
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doInvoke(eu.etaxonomy.cdm.io.common.IoStateBase)
87
	 */
88
	@Override
89
	protected void doInvoke(PesiExportState state) {
90
		try {
91
			logger.error("*** Started Making " + pluralString + " ...");
92
	
93
			// Get the limit for objects to save within a single transaction.
94
			int limit = state.getConfig().getLimitSave();
95

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
491
		return mapping;
492
	}
493

    
494
}
(5-5/6)