Project

General

Profile

Download (16.7 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
@Component
50
public class PesiOccurrenceExport_Old extends PesiExportBase {
51

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

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

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

    
66
	public PesiOccurrenceExport_Old() {
67
		super();
68
	}
69

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
154
									}
155

    
156
									setDistribution(null);
157
								}
158

    
159
							}
160
						}
161
					}
162
				}
163

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
484
		return mapping;
485
	}
486

    
487
}
(5-5/6)