Project

General

Profile

Download (44.3 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.EnumSet;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21

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

    
26
import eu.etaxonomy.cdm.io.berlinModel.BerlinModelTransformer;
27
import eu.etaxonomy.cdm.io.common.DbExportStateBase;
28
import eu.etaxonomy.cdm.io.common.Source;
29
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
30
import eu.etaxonomy.cdm.io.common.mapping.out.CollectionExportMapping;
31
import eu.etaxonomy.cdm.io.common.mapping.out.DbAnnotationMapper;
32
import eu.etaxonomy.cdm.io.common.mapping.out.DbAreaMapper;
33
import eu.etaxonomy.cdm.io.common.mapping.out.DbConstantMapper;
34
import eu.etaxonomy.cdm.io.common.mapping.out.DbDescriptionElementTaxonMapper;
35
import eu.etaxonomy.cdm.io.common.mapping.out.DbDistributionStatusMapper;
36
import eu.etaxonomy.cdm.io.common.mapping.out.DbExportIgnoreMapper;
37
import eu.etaxonomy.cdm.io.common.mapping.out.DbLanguageMapper;
38
import eu.etaxonomy.cdm.io.common.mapping.out.DbNullMapper;
39
import eu.etaxonomy.cdm.io.common.mapping.out.DbObjectMapper;
40
import eu.etaxonomy.cdm.io.common.mapping.out.DbOriginalNameMapper;
41
import eu.etaxonomy.cdm.io.common.mapping.out.DbSimpleFilterMapper;
42
import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
43
import eu.etaxonomy.cdm.io.common.mapping.out.DbTextDataMapper;
44
import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
45
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
46
import eu.etaxonomy.cdm.model.common.CdmBase;
47
import eu.etaxonomy.cdm.model.common.Extension;
48
import eu.etaxonomy.cdm.model.common.ExtensionType;
49
import eu.etaxonomy.cdm.model.common.Language;
50
import eu.etaxonomy.cdm.model.common.LanguageString;
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.reference.OriginalSourceType;
66
import eu.etaxonomy.cdm.model.taxon.Taxon;
67
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
68
import eu.etaxonomy.cdm.profiler.ProfilerController;
69
/**
70
 * The export class for {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase DescriptionElements}.<p>
71
 * Inserts into DataWarehouse database table <code>Note</code>.<p>
72
 * It is divided into two phases:<ul>
73
 * <li>Phase 1:	Export of DescriptionElements as Notes.
74
 * <li>Phase 2:	Export of TaxonName extensions <code>taxComment</code>, <code>fauComment</code> and <code>fauExtraCodes</code> as Notes.</ul>
75
 * @author e.-m.lee
76
 * @since 23.02.2010
77
 * @author a.mueller
78
 */
79
@Component
80
public class PesiDescriptionExport extends PesiExportBase {
81

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

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

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

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

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

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

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

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

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

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

    
128
			success &= doDelete(state);
129

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

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

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

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

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

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

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

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

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

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

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

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

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

    
187
		List<Taxon> taxonList = null;
188

    
189
		TransactionStatus txStatus = startTransaction(true);
190

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

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

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

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

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

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

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

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

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

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

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

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

    
273
				TaxonName name = desc.getTaxonName();
274

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

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

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

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

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

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

    
327
	    boolean success = true;
328

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
655
		return true;
656
	}
657

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

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

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

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

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

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

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

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

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

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

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

    
790

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

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

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

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

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

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

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

    
862
//******************************* MAPPINGS ********************************************
863

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

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

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

    
881
//		mapping.addMapper(MethodMapper.NewInstance("Region", this));
882
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
883

    
884
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
885

    
886
		mapping.addCollectionMapping(getNoteSourceMapping());
887
		return mapping;
888
	}
889

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

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

    
911
		mapping.addMapper(IdMapper.NewInstance("OccurrenceId"));
912
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
913
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("TaxonFullNameCache", true, true, null));
914

    
915
		mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaFk", ! IS_CACHE));
916
		mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaNameCache", IS_CACHE));
917
		mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusFk", ! IS_CACHE));
918
		mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusCache", IS_CACHE));
919

    
920
//		Use OccurrenceSource table instead
921
		mapping.addMapper(DbNullMapper.NewIntegerInstance("SourceFk"));
922
		mapping.addMapper(DbNullMapper.NewStringInstance("SourceCache"));
923

    
924
		mapping.addMapper(DbAnnotationMapper.NewExludedInstance(getLastActionAnnotationTypes(), "Notes"));
925
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
926

    
927
		mapping.addCollectionMapping(getOccurrenceSourceMapping());
928

    
929
		return mapping;
930
	}
931

    
932
	private CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> getOccurrenceSourceMapping() {
933
		String tableName = "OccurrenceSource";
934
		String collectionAttribute = "sources";
935
		IdMapper parentMapper = IdMapper.NewInstance("OccurrenceFk");
936
		@SuppressWarnings("unchecked")
937
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
938
		        = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
939
		mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource",
940
		        "Sources with idInSource currently handle data lineage"));
941
        mapping.addMapper(DbSimpleFilterMapper.NewAllowedValueInstance("idInSource",
942
              EnumSet.of(OriginalSourceType.PrimaryTaxonomicSource, OriginalSourceType.PrimaryMediaSource, OriginalSourceType.Aggregation),
943
              null, "Only primary taxonomic sources should be exported"));
944
		mapping.addMapper(DbObjectMapper.NewNotNullInstance("Citation", "SourceFk"));
945
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
946
		mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
947
        mapping.addMapper(DbOriginalNameMapper.NewInstance("OldTaxonName", IS_CACHE, null));
948

    
949
		return mapping;
950
	}
951

    
952
	/**
953
	 * Returns the CDM to PESI specific export mappings for additional taxon sources to create a new
954
	 * source for the additional taxon source
955
	 * @see #{@link PesiDescriptionExport#getAdditionalTaxonSourceMapping()}
956
	 * @return The {@link PesiExportMapping PesiExportMapping}.
957
	 */
958
	private PesiExportMapping getAddTaxonSourceSourceMapping() {
959
		PesiExportMapping sourceMapping = new PesiExportMapping(PesiSourceExport.dbTableName);
960

    
961
		sourceMapping.addMapper(IdMapper.NewInstance("SourceId"));
962
		sourceMapping.addMapper(DbConstantMapper.NewInstance("SourceCategoryFk", Types.INTEGER, PesiTransformer.REF_UNRESOLVED));
963
		sourceMapping.addMapper(DbConstantMapper.NewInstance("SourceCategoryCache", Types.VARCHAR, PesiTransformer.REF_STR_UNRESOLVED));
964

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

    
967
		sourceMapping.addMapper(DbTextDataMapper.NewDefaultInstance("NomRefCache"));
968

    
969
		return sourceMapping;
970
	}
971

    
972
	/**
973
	 * Returns the CDM to PESI specific export mappings for additional taxon sources.
974
	 * @see #{@link PesiDescriptionExport#getAddTaxonSourceSourceMapping()}
975
	 * @return The {@link PesiExportMapping PesiExportMapping}.
976
	 */
977
	private PesiExportMapping getAdditionalTaxonSourceMapping() {
978

    
979
		PesiExportMapping mapping = new PesiExportMapping(dbAdditionalSourceTableName);
980

    
981
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this, DescriptionElementBase.class, PesiExportState.class));
982

    
983
		mapping.addMapper(IdMapper.NewInstance("SourceFk"));
984
		mapping.addMapper(DbTextDataMapper.NewDefaultInstance("SourceNameCache"));
985

    
986
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER, PesiTransformer.NOMENCLATURAL_REFERENCE));
987
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, PesiTransformer.STR_NOMENCLATURAL_REFERENCE));
988

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

    
991
		return mapping;
992
	}
993

    
994
	/**
995
	 * Returns the CDM to PESI specific export mappings for common names.
996
	 * @return The {@link PesiExportMapping PesiExportMapping}.
997
	 */
998
	private PesiExportMapping getCommonNamesMapping() {
999
		PesiExportMapping mapping = new PesiExportMapping(dbVernacularTableName);
1000

    
1001
		mapping.addMapper(IdMapper.NewInstance("CommonNameId"));
1002
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
1003

    
1004
		mapping.addMapper(DbStringMapper.NewInstance("Name", "CommonName"));
1005
		mapping.addMapper(DbAreaMapper.NewInstance(CommonTaxonName.class, "Area", "Region", IS_CACHE));
1006

    
1007
		mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageFk", ! IS_CACHE));
1008
		mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageCache", IS_CACHE));
1009

    
1010
//      Use CommonNameSource table instead
1011
        mapping.addMapper(DbNullMapper.NewIntegerInstance("SourceFk"));
1012
        mapping.addMapper(DbNullMapper.NewStringInstance("SourceNameCache"));
1013
        //OLD
1014
//		mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceFk", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , ! IS_CACHE));
1015
//		mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceNameCache", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , IS_CACHE));
1016

    
1017
		//no SpeciesExpertGUID and SpeciesExpertName for E+M according to SQL
1018
        mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
1019

    
1020
	    mapping.addCollectionMapping(getCommonNameSourceMapping());
1021
		return mapping;
1022
	}
1023

    
1024
    private CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> getCommonNameSourceMapping() {
1025
        String tableName = "CommonNameSource";
1026
        String collectionAttribute = "sources";
1027
        IdMapper parentMapper = IdMapper.NewInstance("CommonNameFk");
1028
        @SuppressWarnings("unchecked")
1029
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
1030
                = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
1031
        mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource",
1032
                "Sources with idInSource currently handle data lineage"));
1033
        mapping.addMapper(DbObjectMapper.NewNotNullInstance("Citation", "SourceFk"));
1034
        mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
1035
        mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
1036
        mapping.addMapper(DbOriginalNameMapper.NewInstance("OldTaxonName", IS_CACHE, null));
1037

    
1038
        return mapping;
1039
    }
1040

    
1041
	private PesiExportMapping getImageMapping() {
1042
	    PesiExportMapping mapping = new PesiExportMapping(dbImageTableName);
1043
	    mapping.addMapper(MethodMapper.NewInstance("taxonFk", this.getClass(), "getCurrentTaxonFk", Media.class, PesiExportState.class));
1044
		mapping.addMapper(MethodMapper.NewInstance("img_thumb", this.getClass(), "getMediaThumb", Media.class));
1045
		mapping.addMapper(MethodMapper.NewInstance("img_url", this.getClass(), "getMediaUrl", Media.class));
1046
		return mapping;
1047
	}
1048

    
1049
    @Override
1050
    protected boolean doCheck(PesiExportState state) {
1051
        boolean result = true;
1052
        return result;
1053
    }
1054

    
1055
    @Override
1056
    protected boolean isIgnore(PesiExportState state) {
1057
        return ! state.getConfig().isDoDescription();
1058
    }
1059
}
(4-4/14)