Project

General

Profile

Download (17.1 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
 * @since 02.03.2010
48
 *
49
 */
50
@Component
51
public class PesiOccurrenceExport extends PesiExportBase {
52

    
53
    private static final long serialVersionUID = 1444152605658503549L;
54
    private static final Logger logger = Logger.getLogger(PesiOccurrenceExport.class);
55

    
56
    private static final Class<? extends CdmBase> standardMethodParameter = AnnotatableEntity.class;
57

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

    
67
	public PesiOccurrenceExport() {
68
		super();
69
	}
70

    
71
	@Override
72
	public Class<? extends CdmBase> getStandardMethodParameter() {
73
		return standardMethodParameter;
74
	}
75

    
76
	@Override
77
	protected boolean doCheck(PesiExportState state) {
78
		boolean result = true;
79
		return result;
80
	}
81

    
82
	@Override
83
	protected void doInvoke(PesiExportState state) {
84
		try {
85
			logger.error("*** Started Making " + pluralString + " ...");
86

    
87
			// Get the limit for objects to save within a single transaction.
88
			int limit = state.getConfig().getLimitSave();
89

    
90
			// Stores whether this invoke was successful or not.
91
			boolean success = true;
92

    
93
			// PESI: Clear the database table Occurrence.
94
//			doDelete(state);
95

    
96
			// Get specific mappings: (CDM) Occurrence -> (PESI) Occurrence
97
			PesiExportMapping mapping = getMapping();
98

    
99
			// Initialize the db mapper
100
			mapping.initialize(state);
101

    
102
			// PESI: Create the Occurrences
103
			int count = 0;
104
			int taxonCount = 0;
105
			int pastCount = 0;
106
			TransactionStatus txStatus = null;
107
			List<TaxonBase> list = null;
108

    
109
			// Start transaction
110
			txStatus = startTransaction(true);
111
			logger.error("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
112
			while ((list = getTaxonService().list(null, limit, taxonCount, null, null)).size() > 0) {
113

    
114
				taxonCount += list.size();
115
				logger.error("Fetched " + list.size() + " " + parentPluralString + ".");
116
				for (TaxonBase taxonBase : list) {
117
					if (taxonBase.isInstanceOf(Taxon.class)) {
118

    
119
						// Set the current Taxon
120
						taxon = CdmBase.deproxy(taxonBase, Taxon.class);
121

    
122
						// Determine the TaxonDescriptions
123
						Set<TaxonDescription> taxonDescriptions = taxon.getDescriptions();
124

    
125
						// Determine the DescriptionElements (Citations) for the current Taxon
126
						for (TaxonDescription taxonDescription : taxonDescriptions) {
127
							Set<DescriptionElementBase> descriptionElements = taxonDescription.getElements();
128
							for (DescriptionElementBase descriptionElement : descriptionElements) {
129
								Set<DescriptionElementSource> elementSources = descriptionElement.getSources();
130

    
131
								if (descriptionElement.isInstanceOf(Distribution.class)) {
132
									Distribution distribution = CdmBase.deproxy(descriptionElement, Distribution.class);
133
									setNamedArea(distribution.getArea());
134
									setDistribution(distribution);
135

    
136
									// Differentiate between descriptionElements with and without sources.
137
									if (elementSources.size() == 0 && state.getDbId(descriptionElement) != null) {
138
										if (neededValuesNotNull(descriptionElement, state)) {
139
											doCount(count++, modCount, pluralString);
140
											success &= mapping.invoke(descriptionElement);
141
										}
142
									} else {
143
										for (DescriptionElementSource elementSource : elementSources) {
144
											Reference reference = elementSource.getCitation();
145

    
146
											// Citations can be empty (null): Is it wrong data or just a normal case?
147
											if (reference != null && state.getDbId(reference) != null) {
148
												if (neededValuesNotNull(reference, state)) {
149
													doCount(count++, modCount, pluralString);
150
													success &= mapping.invoke(reference);
151
												}
152
											}
153
										}
154

    
155
									}
156

    
157
									setDistribution(null);
158
								}
159

    
160
							}
161
						}
162
					}
163
				}
164

    
165
				// Commit transaction
166
				commitTransaction(txStatus);
167
				logger.error("Committed transaction.");
168
				logger.error("Exported " + (count - pastCount) + " " + pluralString + ". Total: " + count);
169
				pastCount = count;
170

    
171
				// Start transaction
172
				txStatus = startTransaction(true);
173
				logger.error("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
174
			}
175
			if (list.size() == 0) {
176
				logger.error("No " + parentPluralString + " left to fetch.");
177
			}
178
			list = null;
179
			// Commit transaction
180
			commitTransaction(txStatus);
181
			logger.error("Committed transaction.");
182

    
183
			logger.error("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
184

    
185
			if (!success){
186
			    state.getResult().addError("An error occurred in PesiOccurenExport.doInvoke");
187
			}
188
			return;
189
		} catch (SQLException e) {
190
			e.printStackTrace();
191
			logger.error(e.getMessage());
192
			state.getResult().addException(e);
193
			return;
194
		}
195
	}
196

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

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

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

    
250
	/**
251
	 * Deletes all entries of database tables related to <code>Occurrence</code>.
252
	 * @param state The {@link PesiExportState PesiExportState}.
253
	 * @return Whether the delete operation was successful or not.
254
	 */
255
	protected boolean doDelete(PesiExportState state) {
256
		PesiExportConfigurator pesiConfig = state.getConfig();
257

    
258
		String sql;
259
		Source destination =  pesiConfig.getDestination();
260

    
261
		// Clear Occurrence
262
		sql = "DELETE FROM " + dbTableName;
263
		destination.setQuery(sql);
264
		destination.update(sql);
265
		return true;
266
	}
267

    
268
	/* (non-Javadoc)
269
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
270
	 */
271
	@Override
272
	protected boolean isIgnore(PesiExportState state) {
273
		return ! state.getConfig().isDoOccurrence();
274
	}
275

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

    
293
	/**
294
	 * Returns the <code>TaxonFullNameCache</code> attribute.
295
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
296
	 * @return The <code>TaxonFullNameCache</code> attribute.
297
	 * @see MethodMapper
298
	 */
299
	@SuppressWarnings("unused")
300
	private static String getTaxonFullNameCache(AnnotatableEntity entity) {
301
		String result = null;
302
		result = taxon.getName().getTitleCache();
303
		return result;
304
	}
305

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

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

    
349
	/**
350
	 * @return the distribution
351
	 */
352
	public static Distribution getDistribution() {
353
		return distribution;
354
	}
355

    
356
	/**
357
	 * @param distribution the distribution to set
358
	 */
359
	public static void setDistribution(Distribution distribution) {
360
		PesiOccurrenceExport.distribution = distribution;
361
	}
362

    
363
	/**
364
	 * @return the namedArea
365
	 */
366
	public static NamedArea getNamedArea() {
367
		return namedArea;
368
	}
369

    
370
	/**
371
	 * @param namedArea the namedArea to set
372
	 */
373
	public static void setNamedArea(NamedArea namedArea) {
374
		PesiOccurrenceExport.namedArea = namedArea;
375
	}
376

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

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

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

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

    
456
	/**
457
	 * Returns the <code>Notes</code> attribute.
458
	 * @param entity An {@link AnnotatableEntity AnnotatableEntity}.
459
	 * @return The <code>Notes</code> attribute.
460
	 * @see MethodMapper
461
	 */
462
	@SuppressWarnings("unused")
463
	private static String getNotes(AnnotatableEntity entity) {
464
		// TODO
465
		return null;
466
	}
467

    
468
	/**
469
	 * Returns the CDM to PESI specific export mappings.
470
	 * @return The {@link PesiExportMapping PesiExportMapping}.
471
	 */
472
	private PesiExportMapping getMapping() {
473
		PesiExportMapping mapping = new PesiExportMapping(dbTableName);
474

    
475
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this.getClass(), "getTaxonFk", standardMethodParameter, PesiExportState.class));
476
		mapping.addMapper(MethodMapper.NewInstance("AreaFk", this));
477
		mapping.addMapper(MethodMapper.NewInstance("TaxonFullNameCache", this));
478
		mapping.addMapper(MethodMapper.NewInstance("AreaNameCache", this));
479
		mapping.addMapper(MethodMapper.NewInstance("OccurrenceStatusFk", this));
480
		mapping.addMapper(MethodMapper.NewInstance("OccurrenceStatusCache", this, AnnotatableEntity.class, PesiExportState.class));
481
		mapping.addMapper(MethodMapper.NewInstance("SourceFk", this.getClass(), "getSourceFk", standardMethodParameter, PesiExportState.class));
482
		mapping.addMapper(MethodMapper.NewInstance("SourceCache", this));
483
		mapping.addMapper(MethodMapper.NewInstance("Notes", this));
484

    
485
		return mapping;
486
	}
487

    
488
}
(5-5/6)