Project

General

Profile

Download (44 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;
10

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

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

    
25
import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
26
import eu.etaxonomy.cdm.io.common.DbExportStateBase;
27
import eu.etaxonomy.cdm.io.common.Source;
28
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
29
import eu.etaxonomy.cdm.io.common.mapping.out.CollectionExportMapping;
30
import eu.etaxonomy.cdm.io.common.mapping.out.DbAnnotationMapper;
31
import eu.etaxonomy.cdm.io.common.mapping.out.DbAreaMapper;
32
import eu.etaxonomy.cdm.io.common.mapping.out.DbConstantMapper;
33
import eu.etaxonomy.cdm.io.common.mapping.out.DbDescriptionElementTaxonMapper;
34
import eu.etaxonomy.cdm.io.common.mapping.out.DbDistributionStatusMapper;
35
import eu.etaxonomy.cdm.io.common.mapping.out.DbExportIgnoreMapper;
36
import eu.etaxonomy.cdm.io.common.mapping.out.DbLanguageMapper;
37
import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
38
import eu.etaxonomy.cdm.io.common.mapping.out.DbOriginalNameMapper;
39
import eu.etaxonomy.cdm.io.common.mapping.out.DbSimpleFilterMapper;
40
import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
41
import eu.etaxonomy.cdm.io.common.mapping.out.DbTextDataMapper;
42
import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
43
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
44
import eu.etaxonomy.cdm.model.common.CdmBase;
45
import eu.etaxonomy.cdm.model.common.Extension;
46
import eu.etaxonomy.cdm.model.common.ExtensionType;
47
import eu.etaxonomy.cdm.model.common.Language;
48
import eu.etaxonomy.cdm.model.common.LanguageString;
49
import eu.etaxonomy.cdm.model.common.Marker;
50
import eu.etaxonomy.cdm.model.common.MarkerType;
51
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
52
import eu.etaxonomy.cdm.model.description.DescriptionBase;
53
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
54
import eu.etaxonomy.cdm.model.description.Distribution;
55
import eu.etaxonomy.cdm.model.description.Feature;
56
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
57
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
58
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
59
import eu.etaxonomy.cdm.model.description.TextData;
60
import eu.etaxonomy.cdm.model.location.NamedArea;
61
import eu.etaxonomy.cdm.model.media.Media;
62
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
63
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
64
import eu.etaxonomy.cdm.model.name.TaxonName;
65
import eu.etaxonomy.cdm.model.taxon.Taxon;
66
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
67
import eu.etaxonomy.cdm.profiler.ProfilerController;
68
/**
69
 * The export class for {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase DescriptionElements}.<p>
70
 * Inserts into DataWarehouse database table <code>Note</code>.<p>
71
 * It is divided into two phases:<ul>
72
 * <li>Phase 1:	Export of DescriptionElements as Notes.
73
 * <li>Phase 2:	Export of TaxonName extensions <code>taxComment</code>, <code>fauComment</code> and <code>fauExtraCodes</code> as Notes.</ul>
74
 * @author e.-m.lee
75
 * @since 23.02.2010
76
 * @author a.mueller
77
 */
78
@Component
79
public class PesiDescriptionExport extends PesiExportBase {
80

    
81
    private static final long serialVersionUID = -1486235807814098217L;
82
    private static final Logger logger = Logger.getLogger(PesiDescriptionExport.class);
83

    
84
	private static final Class<? extends CdmBase> standardMethodParameter = DescriptionElementBase.class;
85

    
86
	private static int modCount = 1000;
87
	private static final String dbNoteTableName = "Note";
88
	private static final String dbOccurrenceTableName = "Occurrence";
89
	private static final String dbVernacularTableName = "CommonName";
90
	private static final String dbImageTableName = "Image";
91
	private static final String dbAdditionalSourceTableName = "AdditionalTaxonSource";
92
	private static final String pluralString = "descriptions";
93
	private static final String parentPluralString = "Taxa";
94

    
95
	//decide where to handle them best (configurator, transformer, single method, ...)
96
	private static Set<Integer> excludedNoteCategories = new HashSet<>(Arrays.asList(new Integer[]{250,251,252,253,10,11,13}));
97

    
98
	//debugging
99
	private static int countDescriptions;
100
	private static int countTaxa;
101
	private static int countDistribution;
102
	private static int countAdditionalSources;
103
	private static int countImages;
104
	private static int countNotes;
105

    
106
	private static int countCommonName;
107
	private static int countOccurrence;
108
	private static int countOthers;
109

    
110
	public PesiDescriptionExport() {
111
		super();
112
	}
113

    
114
	@Override
115
	public Class<? extends CdmBase> getStandardMethodParameter() {
116
		return standardMethodParameter;
117
	}
118

    
119
	@Override
120
	protected void doInvoke(PesiExportState state) {
121
		try {
122
			logger.info("*** Started Making " + pluralString + " ...");
123

    
124
			// Stores whether this invoke was successful or not.
125
			boolean success = true;
126

    
127
			success &= doDelete(state);
128

    
129
			// Get specific mappings: (CDM) DescriptionElement -> (PESI) Note
130
			PesiExportMapping notesMapping = getNotesMapping();
131
			notesMapping.initialize(state);
132

    
133
			// Get specific mappings: (CDM) DescriptionElement -> (PESI) Occurrence
134
			PesiExportMapping occurrenceMapping = getOccurrenceMapping();
135
			occurrenceMapping.initialize(state);
136

    
137
			// Get specific mappings: (CDM) DescriptionElement -> (PESI) Additional taxon source
138
			PesiExportMapping addSourceSourceMapping = getAddTaxonSourceSourceMapping();
139
			addSourceSourceMapping.initialize(state);
140
			PesiExportMapping additionalSourceMapping = getAdditionalTaxonSourceMapping();
141
			additionalSourceMapping.initialize(state);
142

    
143
			// Get specific mappings: (CDM) DescriptionElement -> (PESI) Common name
144

    
145
			PesiExportMapping vernacularMapping = getCommonNamesMapping();
146
			vernacularMapping.initialize(state);
147

    
148
			// Get specific mappings: (CDM) DescriptionElement -> (PESI) Image
149
			PesiExportMapping imageMapping = getImageMapping();
150
			imageMapping.initialize(state);
151

    
152
			// Taxon Descriptions
153
			success &= doPhase01(state, notesMapping, occurrenceMapping, addSourceSourceMapping, additionalSourceMapping, vernacularMapping, imageMapping);
154

    
155
			// Name Descriptions
156
			success &= doPhase01b(state, notesMapping, occurrenceMapping, addSourceSourceMapping, additionalSourceMapping, vernacularMapping, imageMapping);
157

    
158
			logger.info("PHASE 2...");
159
			success &= doPhase02(state);
160

    
161
			logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
162

    
163
			if (!success){
164
				state.getResult().addError("An unknown problem occurred");
165
			}
166
			return;
167
		} catch (SQLException e) {
168
			e.printStackTrace();
169
			logger.error(e.getMessage());
170
			state.getResult().addException(e, e.getMessage());
171
		}
172
	}
173

    
174
	//PHASE 01: Description Elements
175
	private boolean doPhase01(PesiExportState state, PesiExportMapping notesMapping, PesiExportMapping occurrenceMapping, PesiExportMapping addSourceSourceMapping,
176
			PesiExportMapping additionalSourceMapping, PesiExportMapping vernacularMapping, PesiExportMapping imageMapping) throws SQLException {
177

    
178
//	    System.out.println("PHASE 1 of description import");
179
	    logger.info("PHASE 1...");
180
		int count = 0;
181
		int pastCount = 0;
182
		boolean success = true;
183
		//int limit = state.getConfig().getLimitSave();
184
		int limit = 1000;
185

    
186
		List<Taxon> taxonList = null;
187

    
188
		TransactionStatus txStatus = startTransaction(true);
189

    
190
		if (logger.isDebugEnabled()){
191
		    logger.info("Started new transaction. Fetching some " + parentPluralString + " (max: " + limit + ") ...");
192
		    logger.debug("Start snapshot, before starting loop");
193
		    ProfilerController.memorySnapshot();
194
		}
195

    
196
		List<String> propPath = Arrays.asList(new String[]{"descriptions.elements.*"});
197
		int partitionCount = 0;
198
		while ((taxonList = getNextTaxonPartition(Taxon.class, limit, partitionCount++, propPath )) != null   ) {
199

    
200
			if (logger.isDebugEnabled()) {
201
                logger.info("Fetched " + taxonList.size() + " " + parentPluralString + ". Exporting...");
202
            }
203

    
204
			for (Taxon taxon : taxonList) {
205
				countTaxa++;
206
				doCount(count++, modCount, parentPluralString);
207
				state.setCurrentTaxon(taxon);
208
				if (!taxon.getDescriptions().isEmpty()){
209
					success &= handleSingleTaxon(taxon, state, notesMapping, occurrenceMapping, addSourceSourceMapping,
210
						additionalSourceMapping, vernacularMapping, imageMapping);
211
				}
212
			}
213
			taxonList = null;
214
			state.setCurrentTaxon(null);
215

    
216
			// Commit transaction
217
			commitTransaction(txStatus);
218
			logger.info("Exported " + (count - pastCount) + " " + parentPluralString + ". Total: " + count + " (Phase 01)");
219
			pastCount = count;
220
			ProfilerController.memorySnapshot();
221
			// Start transaction
222
			txStatus = startTransaction(true);
223
			if(logger.isDebugEnabled()) {
224
                logger.info("Started new transaction. Fetching some " + parentPluralString + " (max: " + limit + ") for description import ...");
225
            }
226
		}
227

    
228
		logger.info("No " + parentPluralString + " left to fetch.");
229
		logger.info("Partition: " + partitionCount);
230
		logger.info("Taxa: " + countTaxa);
231
		logger.info("Desc: " + countDescriptions);
232
		logger.info("Distr: " + countDistribution);
233
		logger.info("Occur: " + countOccurrence);
234
		logger.info("Commons: " + countCommonName);
235
		logger.info("AddSrc: " + countAdditionalSources);
236
		logger.info("Images: " + countImages);
237
		logger.info("Notes: " + countNotes);
238
		logger.info("Others: " + countOthers);
239

    
240
		// Commit transaction
241
		commitTransaction(txStatus);
242
		logger.debug("Committed transaction.");
243
		return success;
244
	}
245

    
246
	//PHASE 01b: Name Descriptions
247
	private boolean doPhase01b(PesiExportState state, PesiExportMapping notesMapping, PesiExportMapping occurrenceMapping, PesiExportMapping addSourceSourceMapping,
248
			PesiExportMapping additionalSourceMapping, PesiExportMapping vernacularMapping, PesiExportMapping imageMapping) throws SQLException {
249
		logger.info("PHASE 1b...");
250
		int count = 0;
251
		int pastCount = 0;
252
		boolean success = true;
253
		//int limit = state.getConfig().getLimitSave();
254
		int limit = 2000;
255
		List<TaxonNameDescription> nameDescList = null;
256

    
257
		TransactionStatus txStatus = startTransaction(true);
258
		logger.info("Started new transaction. Fetching some name descriptions (max: " + limit + ") ...");
259
		List<String> propPath = Arrays.asList(new String[]{"descriptions.elements.*"});
260

    
261
		//name descriptions
262
		int partitionCount = 0;
263
		while ((nameDescList = getNextNameDescriptionPartition( limit, partitionCount++, propPath )) != null   ) {
264

    
265
			logger.info("Fetched " + nameDescList.size() + " name descriptions. Exporting...");
266

    
267
			for (TaxonNameDescription desc : nameDescList) {
268
				countTaxa++;
269
				doCount(count++, modCount, "name descriptions");
270
				boolean isImageGallery = desc.isImageGallery();
271

    
272
				TaxonName name = desc.getTaxonName();
273

    
274
				for (DescriptionElementBase element : desc.getElements()){
275
					if (isPurePesiName(name)){
276
						success &= handleDescriptionElement(state, notesMapping, occurrenceMapping, vernacularMapping, imageMapping,
277
								addSourceSourceMapping, additionalSourceMapping, isImageGallery, element);
278
					}else{
279
						for (TaxonBase<?> taxonBase : name.getTaxonBases()){
280
							if (isPesiTaxon(taxonBase)){
281
								state.setCurrentTaxon(taxonBase);
282
								success &= handleDescriptionElement(state, notesMapping, occurrenceMapping, vernacularMapping, imageMapping,
283
										addSourceSourceMapping, additionalSourceMapping, isImageGallery, element);
284
								state.setSourceForAdditionalSourceCreated(true);
285
							}
286
						}
287
						state.setSourceForAdditionalSourceCreated(false);
288
					}
289
				}
290
			}
291
			nameDescList = null;
292
			state.setCurrentTaxon(null);
293

    
294
			// Commit transaction
295
			commitTransaction(txStatus);
296
			logger.info("Exported " + (count - pastCount) + " name descriptions. Total: " + count);
297
			pastCount = count;
298

    
299
			// Start transaction
300
			txStatus = startTransaction(true);
301
			logger.info("Started new transaction. Fetching some name descriptions (max: " + limit + ") for description import ...");
302
		}
303

    
304
		logger.info("No " + parentPluralString + " left to fetch.");
305
		logger.info("Partition: " + partitionCount);
306
		logger.info("Taxa: " + countTaxa);
307
		logger.info("Desc: " + countDescriptions);
308
		logger.info("Distr: " + countDistribution);
309
		logger.info("Occur: " + countOccurrence);
310
		logger.info("Commons: " + countCommonName);
311
		logger.info("AddSrc: " + countAdditionalSources);
312
		logger.info("Images: " + countImages);
313
		logger.info("Notes: " + countNotes);
314
        logger.info("Others: " + countOthers);
315

    
316
		// Commit transaction
317
		commitTransaction(txStatus);
318
		logger.debug("Committed transaction.");
319
		return success;
320
	}
321

    
322
	private boolean handleSingleTaxon(Taxon taxon, PesiExportState state, PesiExportMapping notesMapping, PesiExportMapping occurrenceMapping,
323
			PesiExportMapping addSourceSourceMapping, PesiExportMapping additionalSourceMapping,
324
			PesiExportMapping vernacularMapping, PesiExportMapping imageMapping) throws SQLException {
325

    
326
	    boolean success = true;
327

    
328
		Set<DescriptionBase<?>> descriptions = new HashSet<>();
329
		descriptions.addAll(taxon.getDescriptions());
330

    
331
		for (DescriptionBase<?> desc : descriptions){
332
			boolean isImageGallery = desc.isImageGallery();
333
			for (DescriptionElementBase element : desc.getElements()){
334
				success &= handleDescriptionElement(state, notesMapping, occurrenceMapping, vernacularMapping, imageMapping,
335
						addSourceSourceMapping, additionalSourceMapping, isImageGallery, element);
336
				countDescriptions++;
337
			}
338
		}
339
		if (logger.isDebugEnabled()) {
340
            logger.info("number of handled decriptionelements " + countDescriptions);
341
        }
342
		descriptions = null;
343
		return success;
344
	}
345

    
346
	private boolean handleDescriptionElement(PesiExportState state, PesiExportMapping notesMapping,
347
			PesiExportMapping occurrenceMapping, PesiExportMapping vernacularMapping, PesiExportMapping imageMapping,
348
			PesiExportMapping addSourceSourceMapping, PesiExportMapping additionalSourceMapping, boolean isImageGallery, DescriptionElementBase element) throws SQLException {
349

    
350
	    try {
351
			boolean success = true;
352
			if (isImageGallery){
353
				for (Media media : element.getMedia()){
354
				    countImages++;
355
				    success &= imageMapping.invoke(media);
356
				}
357
			}else if (isCommonName(element)){
358
				countCommonName++;
359
				if (element.isInstanceOf(TextData.class)){
360
					//we do not import text data common names
361
				}else{
362
					success &= vernacularMapping.invoke(element);
363
				}
364
			}else if (isOccurrence(element)){
365
				countOccurrence++;
366
				Distribution distribution = CdmBase.deproxy(element, Distribution.class);
367
				MarkerType markerType = getUuidMarkerType(PesiTransformer.uuidMarkerTypeHasNoLastAction, state);
368
				distribution.addMarker(Marker.NewInstance(markerType, true));
369
				if (!isPesiDistribution(state, distribution)){
370
				    logger.debug("Distribution is not PESI distribution: " + distribution.toString());
371
				}else{
372
					countDistribution++;
373
					try{
374
					    success &=occurrenceMapping.invoke(distribution);
375
					}catch(Exception e){
376
					    System.err.println(distribution.getInDescription().getTitleCache());
377
					    e.printStackTrace();
378
					}
379
				}
380
			}else if (isAdditionalTaxonSource(element)){
381
				countAdditionalSources++;
382
				if (! state.isSourceForAdditionalSourceCreated()){
383
					success &= addSourceSourceMapping.invoke(element);
384
				}
385
				success &= additionalSourceMapping.invoke(element);
386
			}else if (isExcludedNote(element)){
387
				//do nothing
388
			}else if (isPesiNote(element)){
389
				countNotes++;
390
				success &= notesMapping.invoke(element);
391
            }else{
392
				countOthers++;
393
				String featureTitle = element.getFeature() == null ? "no feature" :element.getFeature().getTitleCache();
394
				logger.warn("Description element type not yet handled by PESI export: " + element.getUuid() + ", " +  element.getClass() + ", " +  featureTitle);
395
			}
396
			return success;
397
		} catch (Exception e) {
398
			logger.warn("Exception appeared in description element handling: " + e);
399
			e.printStackTrace();
400
			return false;
401
		}
402
	}
403

    
404
    private boolean isExcludedNote(DescriptionElementBase element) {
405
		Integer categoryFk = PesiTransformer.feature2NoteCategoryFk(element.getFeature());
406
		//TODO decide where to handle them best (configurator, transformer, single method, ...)
407
		return (excludedNoteCategories.contains(categoryFk));
408
	}
409

    
410
    boolean isFirstUndefinedStatusWarnung = true;
411
	private boolean isPesiDistribution(PesiExportState state, Distribution distribution) {
412
		//currently we use the E+M summary status to decide if a distribution should be exported
413
		if (distribution.getStatus() == null){
414
			return false;
415
		}else if (distribution.getStatus().getUuid().equals(BerlinModelTransformer.uuidStatusUndefined)){
416
		    if (isFirstUndefinedStatusWarnung){
417
                logger.warn("Status 'undefined' is not mapped to any status for now. Needs further checking. (E+M specific)");
418
                isFirstUndefinedStatusWarnung = false;
419
            }
420
            return false;
421
		}
422

    
423
		//...this may change in future so we keep the following code
424
		//area filter
425
		NamedArea area = distribution.getArea();
426
		if (area == null){
427
			logger.warn("Area is null for distribution " +  distribution.getUuid());
428
			return false;
429
		}else if (area.getUuid().equals(BerlinModelTransformer.euroMedUuid)){
430
			//E+M area only holds endemic status information and therefore is not exported to PESI
431
			return false;
432
//		}else if (area.equals(TdwgAreaProvider.getAreaByTdwgAbbreviation("1"))){
433
//			//Europe area never holds status information (may probably be deleted in E+M)
434
//			return false;
435
//		}else if (area.equals(TdwgArea.getAreaByTdwgAbbreviation("21"))){
436
//			//Macaronesia records should not be exported to PESI
437
//			return false;
438
//		//TODO exclude Russion areas Rs*, and maybe others
439

    
440
		} else {
441
            try {
442
				if (state.getTransformer().getKeyByNamedArea(area) == null){
443
					String warning = "Area (%s,%s) not available in PESI transformer for taxon %s: ";
444
					TaxonBase<?> taxon =  state.getCurrentTaxon();
445
					warning = String.format(warning, area.getTitleCache(), area.getRepresentation(Language.ENGLISH()).getAbbreviatedLabel(),taxon ==null? "-" : taxon.getTitleCache());
446
					logger.warn(warning);
447
					return false;
448
				}
449
			} catch (UndefinedTransformerMethodException e1) {
450
				logger.warn("Area not available in PESI transformer " +  area.getTitleCache());
451
				return false;
452
			}
453
        }
454
		return true;
455
	}
456

    
457
	private boolean isPesiNote(DescriptionElementBase element) {
458
		return (getNoteCategoryFk(element) != null);
459
	}
460

    
461
	private boolean isAdditionalTaxonSource(DescriptionElementBase element) {
462
		Feature feature = element.getFeature();
463
		if (feature == null){
464
			return false;
465
		}
466
		return (feature.equals(Feature.CITATION()) || feature.equals(Feature.ADDITIONAL_PUBLICATION()));
467
	}
468

    
469
	private boolean isOccurrence(DescriptionElementBase element) {
470
		Feature feature = element.getFeature();
471
		if (element.isInstanceOf(Distribution.class)){
472
		    if (!Feature.DISTRIBUTION().equals(feature)){
473
		        logger.warn("Description element has class 'Distribution' but has no feature 'Distribution'");
474
		    }
475
		    return true;
476
		}else if (Feature.DISTRIBUTION().equals(feature)){
477
		    logger.debug("Description element has feature Distribtuion but is not of class 'Distribution'");
478
            return false;
479
		}else{
480
			return false;
481
		}
482
	}
483

    
484
	private boolean isCommonName(DescriptionElementBase element) {
485
		Feature feature = element.getFeature();
486
		if (feature == null){
487
			return false;
488
		}
489
		return (feature.equals(Feature.COMMON_NAME()));
490
	}
491

    
492
	//PHASE 02: Name extensions
493
	private boolean doPhase02(PesiExportState state) {
494
		TransactionStatus txStatus;
495
		boolean success =  true;
496

    
497
		// Get the limit for objects to save within a single transaction.
498
		//int limit = state.getConfig().getLimitSave();
499
		int limit = 2000;
500
		txStatus = startTransaction(true);
501
		ExtensionType taxCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtTaxComment);
502
		ExtensionType fauCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtFauComment);
503
		ExtensionType fauExtraCodesExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtFauExtraCodes);
504
		List<TaxonName> taxonNameList;
505

    
506
		int count = 0;
507
		int pastCount = 0;
508
		Connection connection = state.getConfig().getDestination().getConnection();
509
		if (logger.isDebugEnabled()) {
510
            logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
511
        }
512
		logger.warn("TODO handle extensions on taxon level, not name level (");
513
		while ((taxonNameList = getNameService().list(null, limit, count, null, null)).size() > 0) {
514

    
515
			if(logger.isDebugEnabled()) {
516
                logger.info("Fetched " + taxonNameList.size() + " names. Exporting...");
517
            }
518
			for (TaxonName taxonName : taxonNameList) {
519
				Set<Extension> extensions = taxonName.getExtensions();
520
				for (Extension extension : extensions) {
521
					if (extension.getType().equals(taxCommentExtensionType)) {
522
						String taxComment = extension.getValue();
523
						invokeNotes(taxComment,
524
								PesiTransformer.getNoteCategoryFk(PesiTransformer.uuidExtTaxComment),
525
								PesiTransformer.getNoteCategoryCache(PesiTransformer.uuidExtTaxComment),
526
								null, null, getTaxonKey(taxonName, state),connection);
527
					} else if (extension.getType().equals(fauCommentExtensionType)) {
528
						String fauComment = extension.getValue();
529
						invokeNotes(fauComment,
530
								PesiTransformer.getNoteCategoryFk(PesiTransformer.uuidExtFauComment),
531
								PesiTransformer.getNoteCategoryCache(PesiTransformer.uuidExtFauComment),
532
								null, null, getTaxonKey(taxonName, state),connection);
533
					} else if (extension.getType().equals(fauExtraCodesExtensionType)) {
534
						String fauExtraCodes = extension.getValue();
535
						invokeNotes(fauExtraCodes,
536
								PesiTransformer.getNoteCategoryFk(PesiTransformer.uuidExtFauExtraCodes),
537
								PesiTransformer.getNoteCategoryCache(PesiTransformer.uuidExtFauExtraCodes),
538
								null, null, getTaxonKey(taxonName, state),connection);
539
					}
540
				}
541

    
542
				doCount(count++, modCount, parentPluralString);
543
			}
544

    
545
			// Commit transaction
546
			commitTransaction(txStatus);
547
			logger.debug("Committed transaction.");
548
			logger.info("Exported " + (count - pastCount) + " names. Total: " + count + " (Phase 02)");
549
			pastCount = count;
550

    
551
			// Start transaction
552
			txStatus = startTransaction(true);
553
			if (logger.isDebugEnabled()) {
554
                logger.info("Started new transaction. Fetching some names first (max: " + limit + ") ...");
555
            }
556
		}
557
		// Commit transaction
558
		commitTransaction(txStatus);
559
		logger.debug("Committed transaction.");
560
		return success;
561
	}
562

    
563
	private void invokeNotes(String note, Integer noteCategoryFk,
564
			String noteCategoryCache, Integer languageFk, String languageCache,
565
			Integer taxonFk, Connection connection) {
566

    
567
	    String notesSql = "UPDATE Note SET Note_1 = ?, NoteCategoryFk = ?, NoteCategoryCache = ?, LanguageFk = ?, LanguageCache = ? WHERE TaxonFk = ?";
568
		try {
569
			PreparedStatement notesStmt = connection.prepareStatement(notesSql);
570

    
571
			if (note != null) {
572
				notesStmt.setString(1, note);
573
			} else {
574
				notesStmt.setObject(1, null);
575
			}
576

    
577
			if (noteCategoryFk != null) {
578
				notesStmt.setInt(2, noteCategoryFk);
579
			} else {
580
				notesStmt.setObject(2, null);
581
			}
582

    
583
			if (noteCategoryCache != null) {
584
				notesStmt.setString(3, noteCategoryCache);
585
			} else {
586
				notesStmt.setObject(3, null);
587
			}
588

    
589
			if (languageFk != null) {
590
				notesStmt.setInt(4, languageFk);
591
			} else {
592
				notesStmt.setObject(4, null);
593
			}
594

    
595
			if (languageCache != null) {
596
				notesStmt.setString(5, languageCache);
597
			} else {
598
				notesStmt.setObject(5, null);
599
			}
600

    
601
			if (taxonFk != null) {
602
				notesStmt.setInt(6, taxonFk);
603
			} else {
604
				notesStmt.setObject(6, null);
605
			}
606

    
607
			notesStmt.executeUpdate();
608
		} catch (SQLException e) {
609
			logger.error("Note could not be created: " + note);
610
			e.printStackTrace();
611
		}
612
	}
613

    
614
	/**
615
	 * Deletes all entries of database tables related to <code>Note</code>.
616
	 * @param state The PesiExportState
617
	 * @return Whether the delete operation was successful or not.
618
	 */
619
	protected boolean doDelete(PesiExportState state) {
620
	    Source destination = state.getConfig().getDestination();
621

    
622
		// Clear NoteSource
623
		String sql = "DELETE FROM NoteSource";
624
		destination.update(sql);
625
		// Clear Note
626
		sql = "DELETE FROM Note "; // + dbNoteTableName;
627
		destination.update(sql);
628

    
629
	    // Clear OccurrenceSource
630
        sql = "DELETE FROM OccurrenceSource ";
631
        destination.update(sql);
632
        // Clear Occurrence
633
        sql = "DELETE FROM Occurrence ";
634
        destination.update(sql);
635

    
636
        // Clear Image
637
        sql = "DELETE FROM Image ";
638
        destination.update(sql);
639

    
640
        // Clear CommonName
641
        sql = "DELETE FROM CommonNameSource ";
642
        destination.update(sql);
643
        sql = "DELETE FROM CommonName ";
644
        destination.update(sql);
645

    
646
        // Clear AdditionalTaxonSource
647
        sql = "DELETE FROM AdditionalTaxonSource WHERE SourceFk >= 2000000 ";
648
        destination.update(sql);
649

    
650
        // Clear Sources for AdditionalTaxonSource
651
        sql = "DELETE FROM Source WHERE SourceId >= 2000000 ";
652
        destination.update(sql);
653

    
654
		return true;
655
	}
656

    
657
	/**
658
	 * Returns the <code>Note_2</code> attribute.
659
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
660
	 * @return The <code>Note_2</code> attribute.
661
	 * @see MethodMapper
662
	 */
663
	@SuppressWarnings("unused") //used for mapper
664
	private static String getNote_2(DescriptionElementBase element) {
665
		//E+M map links -> medium
666
		if (element.getFeature() != null && element.getFeature().getUuid().equals(BerlinModelTransformer.uuidFeatureMaps)){
667
			String text = CdmBase.deproxy(element, TextData.class).getText(Language.ENGLISH());
668
			if (text.contains("medium")){
669
				return "medium";
670
			}
671
		}
672
		return null;
673
	}
674

    
675
	/**
676
	 * Returns the <code>NoteCategoryFk</code> attribute.
677
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
678
	 * @return The <code>NoteCategoryFk</code> attribute.
679
	 * @see MethodMapper
680
	 */
681
	private static Integer getNoteCategoryFk(DescriptionElementBase descriptionElement) {
682
		Integer result = null;
683
		result = PesiTransformer.feature2NoteCategoryFk(descriptionElement.getFeature());
684
		//TODO decide where to handle them best (configurator, transformer, single method, ...)
685
		if (excludedNoteCategories.contains(result)){
686
			result = null;
687
		}
688
		return result;
689
	}
690

    
691
	/**
692
	 * Returns the <code>NoteCategoryCache</code> attribute.
693
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
694
	 * @return The <code>NoteCategoryCache</code> attribute.
695
	 * @see MethodMapper
696
	 */
697
	@SuppressWarnings("unused")
698
	private static String getNoteCategoryCache(DescriptionElementBase descriptionElement, PesiExportState state) {
699
		return state.getTransformer().getCacheByFeature(descriptionElement.getFeature());
700
	}
701

    
702
	/**
703
	 * Returns the <code>LanguageFk</code> attribute.
704
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
705
	 * @return The <code>LanguageFk</code> attribute.
706
	 * @see MethodMapper
707
	 */
708
	@SuppressWarnings("unused")
709
	private static Integer getLanguageFk(DescriptionElementBase descriptionElement) {
710
		Language language = getLanguage(descriptionElement);
711

    
712
		return PesiTransformer.language2LanguageId(language);
713
	}
714

    
715
	/**
716
	 * Returns the <code>LanguageCache</code> attribute.
717
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
718
	 * @return The <code>LanguageCache</code> attribute.
719
	 * @throws UndefinedTransformerMethodException
720
	 * @see MethodMapper
721
	 */
722
	@SuppressWarnings("unused")
723
	private static String getLanguageCache(DescriptionElementBase descriptionElement, PesiExportState state) throws UndefinedTransformerMethodException {
724
		Language language = getLanguage(descriptionElement);
725
		return state.getTransformer().getCacheByLanguage(language);
726
	}
727

    
728
	private static Language getLanguage(DescriptionElementBase descriptionElement) {
729
		Language language = null;
730

    
731
		Map<Language, LanguageString> multilanguageText = null;
732
		if (descriptionElement.isInstanceOf(CommonTaxonName.class)) {
733
			CommonTaxonName commonTaxonName = CdmBase.deproxy(descriptionElement, CommonTaxonName.class);
734
			language = commonTaxonName.getLanguage();
735
		} else if (descriptionElement.isInstanceOf(TextData.class)) {
736
			TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
737
			multilanguageText = textData.getMultilanguageText();
738
		} else if (descriptionElement.isInstanceOf(IndividualsAssociation.class)) {
739
			IndividualsAssociation individualsAssociation = CdmBase.deproxy(descriptionElement, IndividualsAssociation.class);
740
			multilanguageText = individualsAssociation.getDescription();
741
		} else if (descriptionElement.isInstanceOf(TaxonInteraction.class)) {
742
			TaxonInteraction taxonInteraction = CdmBase.deproxy(descriptionElement, TaxonInteraction.class);
743
			multilanguageText = taxonInteraction.getDescription();
744
		} else {
745
			logger.debug("Given descriptionElement does not support languages. Hence LanguageCache could not be determined: " + descriptionElement.getUuid());
746
		}
747

    
748
		if (multilanguageText != null) {
749
			Set<Language> languages = multilanguageText.keySet();
750

    
751
			// TODO: Think of something more sophisticated than this
752
			if (languages.size() > 0) {
753
				language = languages.iterator().next();
754
			}
755
			if (languages.size() > 1){
756
				logger.warn("There is more than 1 language for a given description (" + descriptionElement.getClass().getSimpleName() + "):" + descriptionElement.getUuid());
757
			}
758
		}
759
		return language;
760
	}
761

    
762
//	/**
763
//	 * Returns the <code>Region</code> attribute.
764
//	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
765
//	 * @return The <code>Region</code> attribute.
766
//	 * @see MethodMapper
767
//	 */
768
//	@SuppressWarnings("unused")
769
//	private static String getRegion(DescriptionElementBase descriptionElement) {
770
//		String result = null;
771
//		DescriptionBase<?> inDescription = descriptionElement.getInDescription();
772
//
773
//		// Area information are associated to TaxonDescriptions and Distributions.
774
//		if (descriptionElement.isInstanceOf(Distribution.class)) {
775
//			Distribution distribution = CdmBase.deproxy(descriptionElement, Distribution.class);
776
//			result = PesiTransformer.area2AreaCache(distribution.getArea());
777
//		} else if (inDescription != null && inDescription.isInstanceOf(TaxonDescription.class)) {
778
//			TaxonDescription taxonDescription = CdmBase.deproxy(inDescription, TaxonDescription.class);
779
//			Set<NamedArea> namedAreas = taxonDescription.getGeoScopes();
780
//			if (namedAreas.size() == 1) {
781
//				result = PesiTransformer.area2AreaCache(namedAreas.iterator().next());
782
//			} else if (namedAreas.size() > 1) {
783
//				logger.warn("This TaxonDescription contains more than one NamedArea: " + taxonDescription.getTitleCache());
784
//			}
785
//		}
786
//		return result;
787
//	}
788

    
789

    
790
	/**
791
	 * @param state The {@link DbExportStateBase DbExportState}.
792
	 * @return
793
	 */
794
	@SuppressWarnings("unused")  //used by mapper
795
	private static Integer getTaxonFk(DescriptionElementBase deb, PesiExportState state) {
796
		TaxonBase<?> entity = state.getCurrentTaxon();
797
		return state.getDbId(entity);
798
	}
799

    
800
	/**
801
	 * Returns the TaxonFk for a given TaxonName.
802
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
803
	 * @param state The {@link DbExportStateBase DbExportState}.
804
	 * @return
805
	 */
806
	private static Integer getTaxonKey(TaxonName taxonName, DbExportStateBase<?, PesiTransformer> state) {
807
		return state.getDbId(taxonName);
808
	}
809

    
810
	/**
811
	 * Returns the <code>FullName</code> attribute.
812
	 * @param taxonName The {@link NonViralName NonViralName}.
813
	 * @return The <code>FullName</code> attribute.
814
	 * @see MethodMapper
815
	 */
816
	@SuppressWarnings("unused")
817
	private static String getTaxonFullNameCache(DescriptionElementBase deb, PesiExportState state) {
818

    
819
		TaxonBase<?> taxon =  state.getCurrentTaxon();
820
		TaxonName taxonName = taxon.getName();
821
		TaxonName nvn = CdmBase.deproxy(taxonName);
822
		String result = getCacheStrategy(nvn).getTitleCache(nvn);
823
		return result;
824
	}
825

    
826
    @SuppressWarnings("unused")  //used by mapper
827
    private static Integer getCurrentTaxonFk(Media media, PesiExportState state) {
828
        return state.getDbId(state.getCurrentTaxon());
829
    }
830

    
831
    @SuppressWarnings("unused")  //used by mapper
832
    private static String getMediaThumb(Media media) {
833
        String startsWith = "http://images.vliz.be/thumbs/";
834
        String result = null;
835
        for (MediaRepresentation rep : media.getRepresentations()){
836
            for (MediaRepresentationPart part : rep.getParts()){
837
                String strUrl = part.getUri().toString();
838
                if (strUrl.startsWith(startsWith)){
839
                    result = part.getUri().toString();
840
                }
841
            }
842
        }
843
        return result;
844
    }
845

    
846
    @SuppressWarnings("unused")  //used by mapper
847
    private static String getMediaUrl(Media media) {
848
        String startsWith = "http://www.marbef.org/data/aphia.php?p=image&pic=";
849
        String result = null;
850
        for (MediaRepresentation rep : media.getRepresentations()){
851
            for (MediaRepresentationPart part : rep.getParts()){
852
                String strUrl = part.getUri().toString();
853
                if (strUrl.startsWith(startsWith)){
854
                    result = part.getUri().toString();
855
                }
856
            }
857
        }
858
        return result;
859
    }
860

    
861
//******************************* MAPPINGS ********************************************
862

    
863
	/**
864
	 * Returns the CDM to PESI specific export mappings for PESI notes.
865
	 * @return The {@link PesiExportMapping PesiExportMapping}.
866
	 */
867
	private PesiExportMapping getNotesMapping() {
868
		PesiExportMapping mapping = new PesiExportMapping(dbNoteTableName);
869

    
870
		mapping.addMapper(IdMapper.NewInstance("NoteId"));
871
		mapping.addMapper(DbTextDataMapper.NewDefaultInstance("Note_1"));
872
		//TODO
873
		mapping.addMapper(MethodMapper.NewInstance("Note_2", this, standardMethodParameter));
874
		mapping.addMapper(MethodMapper.NewInstance("NoteCategoryFk", this, standardMethodParameter ));
875

    
876
		mapping.addMapper(MethodMapper.NewInstance("NoteCategoryCache", this, standardMethodParameter, PesiExportState.class ));
877
		mapping.addMapper(MethodMapper.NewInstance("LanguageFk", this));
878
		mapping.addMapper(MethodMapper.NewInstance("LanguageCache", this, standardMethodParameter, PesiExportState.class));
879

    
880
//		mapping.addMapper(MethodMapper.NewInstance("Region", this));
881
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
882
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
883
		mapping.addCollectionMapping(getNoteSourceMapping());
884
		return mapping;
885
	}
886

    
887
	private CollectionExportMapping<PesiExportState, PesiExportConfigurator,PesiTransformer> getNoteSourceMapping() {
888
		String tableName = "NoteSource";
889
		String collectionAttribute = "sources";
890
		IdMapper parentMapper = IdMapper.NewInstance("NoteFk");
891
		@SuppressWarnings("unchecked")
892
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
893
                = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
894
		mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource", "Sources with idInSource currently handle data lineage"));
895
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
896
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
897
		mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
898
		return mapping;
899
	}
900

    
901
	/**
902
	 * Returns the CDM to PESI specific export mappings for occurrences.
903
	 * @return The {@link PesiExportMapping PesiExportMapping}.
904
	 */
905
	private PesiExportMapping getOccurrenceMapping() {
906
		PesiExportMapping mapping = new PesiExportMapping(dbOccurrenceTableName);
907

    
908
		mapping.addMapper(IdMapper.NewInstance("OccurrenceId"));
909
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
910
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("TaxonFullNameCache", true, true, null));
911

    
912
		mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaFk", ! IS_CACHE));
913
		mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaNameCache", IS_CACHE));
914
		mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusFk", ! IS_CACHE));
915
		mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusCache", IS_CACHE));
916

    
917
//		Use OccurrenceSource table instead
918
		mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceFk", "Use OccurrenceSource table for sources instead"));
919
		mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceCache", "Use OccurrenceSource table for sources instead"));
920

    
921
		mapping.addMapper(DbAnnotationMapper.NewExludedInstance(getLastActionAnnotationTypes(), "Notes"));
922
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
923
		mapping.addCollectionMapping(getOccurrenceSourceMapping());
924

    
925
		return mapping;
926
	}
927

    
928
	private CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> getOccurrenceSourceMapping() {
929
		String tableName = "OccurrenceSource";
930
		String collectionAttribute = "sources";
931
		IdMapper parentMapper = IdMapper.NewInstance("OccurrenceFk");
932
		@SuppressWarnings("unchecked")
933
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
934
		        = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
935
		mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource",
936
		        "Sources with idInSource currently handle data lineage"));
937
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
938
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
939
		mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
940
        mapping.addMapper(DbOriginalNameMapper.NewInstance("OldTaxonName", IS_CACHE, null));
941

    
942
		return mapping;
943
	}
944

    
945
	/**
946
	 * Returns the CDM to PESI specific export mappings for additional taxon sources to create a new
947
	 * source for the additional taxon source
948
	 * @see #{@link PesiDescriptionExport#getAdditionalTaxonSourceMapping()}
949
	 * @return The {@link PesiExportMapping PesiExportMapping}.
950
	 */
951
	private PesiExportMapping getAddTaxonSourceSourceMapping() {
952
		PesiExportMapping sourceMapping = new PesiExportMapping(PesiSourceExport.dbTableName);
953

    
954
		sourceMapping.addMapper(IdMapper.NewInstance("SourceId"));
955
		sourceMapping.addMapper(DbConstantMapper.NewInstance("SourceCategoryFk", Types.INTEGER, PesiTransformer.REF_UNRESOLVED));
956
		sourceMapping.addMapper(DbConstantMapper.NewInstance("SourceCategoryCache", Types.VARCHAR, PesiTransformer.REF_STR_UNRESOLVED));
957

    
958
//		sourceMapping.addMapper(MethodMapper.NewInstance("NomRefCache", PesiSourceExport.class, "getNomRefCache", Reference.class));
959

    
960
		sourceMapping.addMapper(DbTextDataMapper.NewDefaultInstance("NomRefCache"));
961

    
962
		return sourceMapping;
963
	}
964

    
965
	/**
966
	 * Returns the CDM to PESI specific export mappings for additional taxon sources.
967
	 * @see #{@link PesiDescriptionExport#getAddTaxonSourceSourceMapping()}
968
	 * @return The {@link PesiExportMapping PesiExportMapping}.
969
	 */
970
	private PesiExportMapping getAdditionalTaxonSourceMapping() {
971

    
972
		PesiExportMapping mapping = new PesiExportMapping(dbAdditionalSourceTableName);
973

    
974
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this, DescriptionElementBase.class, PesiExportState.class));
975

    
976
		mapping.addMapper(IdMapper.NewInstance("SourceFk"));
977
		mapping.addMapper(DbTextDataMapper.NewDefaultInstance("SourceNameCache"));
978

    
979
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER, PesiTransformer.NOMENCLATURAL_REFERENCE));
980
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, PesiTransformer.STR_NOMENCLATURAL_REFERENCE));
981

    
982
		mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceDetail", "SourceDetails not available for additional sources"));
983

    
984
		return mapping;
985
	}
986

    
987
	/**
988
	 * Returns the CDM to PESI specific export mappings for common names.
989
	 * @return The {@link PesiExportMapping PesiExportMapping}.
990
	 */
991
	private PesiExportMapping getCommonNamesMapping() {
992
		PesiExportMapping mapping = new PesiExportMapping(dbVernacularTableName);
993

    
994
		mapping.addMapper(IdMapper.NewInstance("CommonNameId"));
995
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
996

    
997
		mapping.addMapper(DbStringMapper.NewInstance("Name", "CommonName"));
998
		mapping.addMapper(DbAreaMapper.NewInstance(CommonTaxonName.class, "Area", "Region", IS_CACHE));
999

    
1000
		mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageFk", ! IS_CACHE));
1001
		mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageCache", IS_CACHE));
1002

    
1003
//      Use OccurrenceSource table instead
1004
        mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceFk", "Use CommonNameSource table for sources instead"));
1005
        mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceNameCache", "Use CommonNameSource table for sources instead"));
1006
        //OLD
1007
//		mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceFk", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , ! IS_CACHE));
1008
//		mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceNameCache", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , IS_CACHE));
1009

    
1010
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
1011
	    mapping.addCollectionMapping(getCommonNameSourceMapping());
1012
		return mapping;
1013
	}
1014

    
1015
    private CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> getCommonNameSourceMapping() {
1016
        String tableName = "CommonNameSource";
1017
        String collectionAttribute = "sources";
1018
        IdMapper parentMapper = IdMapper.NewInstance("CommonNameFk");
1019
        @SuppressWarnings("unchecked")
1020
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
1021
                = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
1022
        mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource",
1023
                "Sources with idInSource currently handle data lineage"));
1024
        mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
1025
        mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
1026
        mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
1027
        mapping.addMapper(DbOriginalNameMapper.NewInstance("OldTaxonName", IS_CACHE, null));
1028

    
1029
        return mapping;
1030
    }
1031

    
1032
	private PesiExportMapping getImageMapping() {
1033
	    PesiExportMapping mapping = new PesiExportMapping(dbImageTableName);
1034
	    mapping.addMapper(MethodMapper.NewInstance("taxonFk", this.getClass(), "getCurrentTaxonFk", Media.class, PesiExportState.class));
1035
		mapping.addMapper(MethodMapper.NewInstance("img_thumb", this.getClass(), "getMediaThumb", Media.class));
1036
		mapping.addMapper(MethodMapper.NewInstance("img_url", this.getClass(), "getMediaUrl", Media.class));
1037
		return mapping;
1038
	}
1039

    
1040
    @Override
1041
    protected boolean doCheck(PesiExportState state) {
1042
        boolean result = true;
1043
        return result;
1044
    }
1045

    
1046
    @Override
1047
    protected boolean isIgnore(PesiExportState state) {
1048
        return ! state.getConfig().isDoDescription();
1049
    }
1050
}
(4-4/14)