Project

General

Profile

Download (44.4 KB) Statistics
| Branch: | Revision:
1
/**
2
* Copyright (C) 2009 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.io.pesi.out;
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.TdwgAreaProvider;
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.DbObjectMapper;
39
import eu.etaxonomy.cdm.io.common.mapping.out.DbOriginalNameMapper;
40
import eu.etaxonomy.cdm.io.common.mapping.out.DbSimpleFilterMapper;
41
import eu.etaxonomy.cdm.io.common.mapping.out.DbStringMapper;
42
import eu.etaxonomy.cdm.io.common.mapping.out.DbTextDataMapper;
43
import eu.etaxonomy.cdm.io.common.mapping.out.IdMapper;
44
import eu.etaxonomy.cdm.io.common.mapping.out.MethodMapper;
45
import eu.etaxonomy.cdm.io.pesi.erms.ErmsTransformer;
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.common.Marker;
52
import eu.etaxonomy.cdm.model.common.MarkerType;
53
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
54
import eu.etaxonomy.cdm.model.description.DescriptionBase;
55
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
56
import eu.etaxonomy.cdm.model.description.Distribution;
57
import eu.etaxonomy.cdm.model.description.Feature;
58
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
59
import eu.etaxonomy.cdm.model.description.TaxonInteraction;
60
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
61
import eu.etaxonomy.cdm.model.description.TextData;
62
import eu.etaxonomy.cdm.model.location.NamedArea;
63
import eu.etaxonomy.cdm.model.media.Media;
64
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
65
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
66
import eu.etaxonomy.cdm.model.name.TaxonName;
67
import eu.etaxonomy.cdm.model.taxon.Taxon;
68
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
69
import eu.etaxonomy.cdm.profiler.ProfilerController;
70
/**
71
 * The export class for {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase DescriptionElements}.<p>
72
 * Inserts into DataWarehouse database table <code>Note</code>.<p>
73
 * It is divided into two phases:<ul>
74
 * <li>Phase 1:	Export of DescriptionElements as Notes.
75
 * <li>Phase 2:	Export of TaxonName extensions <code>taxComment</code>, <code>fauComment</code> and <code>fauExtraCodes</code> as Notes.</ul>
76
 * @author e.-m.lee
77
 * @since 23.02.2010
78
 * @author a.mueller
79
 */
80
@Component
81
public class PesiDescriptionExport extends PesiExportBase {
82

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

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

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

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

    
100
	//debugging
101
	private static int countDescriptions;
102
	private static int countTaxa;
103
	private static int countDistribution;
104
	private static int countAdditionalSources;
105
	private static int countImages;
106
	private static int countNotes;
107
	private static int countSourceOfSynonymy;
108

    
109
	private static int countCommonName;
110
	private static int countOccurrence;
111
	private static int countOthers;
112

    
113
	public PesiDescriptionExport() {
114
		super();
115
	}
116

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

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

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

    
130
			success &= doDelete(state);
131

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

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

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

    
146
			// Get specific mappings: (CDM) DescriptionElement -> (PESI) Common name
147

    
148
			PesiExportMapping vernacularMapping = getCommonNamesMapping();
149
			vernacularMapping.initialize(state);
150

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

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

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

    
161
			logger.info("PHASE 2...");
162
			success &= doPhase02(state);
163

    
164
			logger.info("*** Finished Making " + pluralString + " ..." + getSuccessString(success));
165

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

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

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

    
189
		List<Taxon> taxonList = null;
190

    
191
		TransactionStatus txStatus = startTransaction(true);
192

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

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

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

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

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

    
231
		logger.info("No " + parentPluralString + " left to fetch.");
232
		logger.info("Partition: " + partitionCount);
233
		logger.info("Taxa: " + countTaxa);
234
		logger.info("Desc: " + countDescriptions);
235
		logger.info("Distr: " + countDistribution);
236
		logger.info("Occur: " + countOccurrence);
237
		logger.info("Commons: " + countCommonName);
238
		logger.info("AddSrc: " + countAdditionalSources);
239
		logger.info("Images: " + countImages);
240
		logger.info("Notes: " + countNotes);
241
	    logger.info("Source of Synonymy: " + countSourceOfSynonymy);
242
		logger.info("Others: " + countOthers);
243

    
244
		// Commit transaction
245
		commitTransaction(txStatus);
246
		logger.debug("Committed transaction.");
247
		return success;
248
	}
249

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

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

    
265
		//name descriptions
266
		int partitionCount = 0;
267
		while ((nameDescList = getNextNameDescriptionPartition( limit, partitionCount++, propPath )) != null   ) {
268

    
269
			logger.info("Fetched " + nameDescList.size() + " name descriptions. Exporting...");
270

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

    
276
				TaxonName name = desc.getTaxonName();
277

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

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

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

    
308
		logger.info("No " + parentPluralString + " left to fetch.");
309
		logger.info("Partition: " + partitionCount);
310
		logger.info("Taxa: " + countTaxa);
311
		logger.info("Desc: " + countDescriptions);
312
		logger.info("Distr: " + countDistribution);
313
		logger.info("Occur: " + countOccurrence);
314
		logger.info("Commons: " + countCommonName);
315
		logger.info("AddSrc: " + countAdditionalSources);
316
		logger.info("Images: " + countImages);
317
		logger.info("Notes: " + countNotes);
318
		logger.info("Source of Synonymy: " + countSourceOfSynonymy);
319
        logger.info("Others: " + countOthers);
320

    
321
		// Commit transaction
322
		commitTransaction(txStatus);
323
		logger.debug("Committed transaction.");
324
		return success;
325
	}
326

    
327
	private boolean handleSingleTaxon(Taxon taxon, PesiExportState state, PesiExportMapping notesMapping, PesiExportMapping occurrenceMapping,
328
			PesiExportMapping addSourceSourceMapping, PesiExportMapping additionalSourceMapping,
329
			PesiExportMapping vernacularMapping, PesiExportMapping imageMapping) throws SQLException {
330

    
331
	    boolean success = true;
332

    
333
		Set<DescriptionBase<?>> descriptions = new HashSet<>();
334
		descriptions.addAll(taxon.getDescriptions());
335

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

    
351
	private boolean handleDescriptionElement(PesiExportState state, PesiExportMapping notesMapping,
352
			PesiExportMapping occurrenceMapping, PesiExportMapping vernacularMapping, PesiExportMapping imageMapping,
353
			PesiExportMapping addSourceSourceMapping, PesiExportMapping additionalSourceMapping, boolean isImageGallery, DescriptionElementBase element) throws SQLException {
354

    
355
	    try {
356
			boolean success = true;
357
			if (isImageGallery){
358
				for (Media media : element.getMedia()){
359
				    countImages++;
360
				    success &= imageMapping.invoke(media);
361
				}
362
			}else if (isCommonName(element)){
363
				countCommonName++;
364
				if (element.isInstanceOf(TextData.class)){
365
					//we do not import text data common names
366
				}else{
367
					success &= vernacularMapping.invoke(element);
368
				}
369
			}else if (isOccurrence(element)){
370
				countOccurrence++;
371
				Distribution distribution = CdmBase.deproxy(element, Distribution.class);
372
				MarkerType markerType = getUuidMarkerType(PesiTransformer.uuidMarkerTypeHasNoLastAction, state);
373
				distribution.addMarker(Marker.NewInstance(markerType, true));
374
				if (isPesiDistribution(state, distribution)){
375
					countDistribution++;
376
					try{
377
					    success &=occurrenceMapping.invoke(distribution);
378
					}catch(Exception e){
379
					    System.err.println(distribution.getInDescription().getTitleCache());
380
					    e.printStackTrace();
381
					}
382
				}else{
383
				    logger.warn("Distribution is not PESI distribution");
384
				}
385
			}else if (isAdditionalTaxonSource(element)){
386
				countAdditionalSources++;
387
				if (! state.isSourceForAdditionalSourceCreated()){
388
					success &= addSourceSourceMapping.invoke(element);
389
				}
390
				success &= additionalSourceMapping.invoke(element);
391
			}else if (isExcludedNote(element)){
392
				//do nothing
393
			}else if (isPesiNote(element)){
394
				countNotes++;
395
				success &= notesMapping.invoke(element);
396

    
397
			}else if (isSourceOfSynonymy(element)){
398
                countSourceOfSynonymy++;
399
                if(countSourceOfSynonymy < 2){
400
                    logger.warn("Source of synonymy not yet implemented!");
401
                }
402
            }else{
403
				countOthers++;
404
				String featureTitle = element.getFeature() == null ? "no feature" :element.getFeature().getTitleCache();
405
				logger.warn("Description element type not yet handled by PESI export: " + element.getUuid() + ", " +  element.getClass() + ", " +  featureTitle);
406
			}
407
			return success;
408
		} catch (Exception e) {
409
			logger.warn("Exception appeared in description element handling: " + e);
410
			e.printStackTrace();
411
			return false;
412
		}
413
	}
414

    
415
    private boolean isSourceOfSynonymy(DescriptionElementBase element) {
416
        if (element.getFeature() == null){
417
            return false;
418
        }else {
419
            return element.getFeature().getUuid().equals(ErmsTransformer.uuidSourceOfSynonymy);
420
        }
421
    }
422

    
423
    private boolean isExcludedNote(DescriptionElementBase element) {
424
		Integer categoryFk = PesiTransformer.feature2NoteCategoryFk(element.getFeature());
425
		//TODO decide where to handle them best (configurator, transformer, single method, ...)
426
		return (excludedNoteCategories.contains(categoryFk));
427
	}
428

    
429
	private boolean isPesiDistribution(PesiExportState state, Distribution distribution) {
430
		//currently we use the E+M summary status to decide if a distribution should be exported
431
		if (distribution.getStatus() == null){
432
			return false;
433
		}
434

    
435
		//...this may change in future so we keep the following code
436
		Integer key;
437
		//area filter
438
		NamedArea area = distribution.getArea();
439
		if (area == null){
440
			logger.warn("Area is null for distribution " +  distribution.getUuid());
441
			return false;
442
		}else if (area.getUuid().equals(BerlinModelTransformer.euroMedUuid)){
443
			//E+M area only holds endemic status information and therefore is not exported to PESI
444
			return false;
445
		}else if (area.equals(TdwgAreaProvider.getAreaByTdwgAbbreviation("1"))){
446
			//Europe area never holds status information (may probably be deleted in E+M)
447
			return false;
448
//		}else if (area.equals(TdwgArea.getAreaByTdwgAbbreviation("21"))){
449
//			//Macaronesia records should not be exported to PESI
450
//			return false;
451
//		//TODO exclude Russion areas Rs*, and maybe ohters
452

    
453
		} else {
454
            try {
455
				if (state.getTransformer().getKeyByNamedArea(area) == null){
456
					String warning = "Area (%s,%s) not available in PESI transformer for taxon %S: ";
457
					TaxonBase<?> taxon =  state.getCurrentTaxon();
458
					warning = String.format(warning, area.getTitleCache(), area.getRepresentation(Language.ENGLISH()).getAbbreviatedLabel(),taxon ==null? "-" : taxon.getTitleCache());
459
					logger.warn(warning);
460
					return false;
461
				}
462
			} catch (UndefinedTransformerMethodException e1) {
463
				logger.warn("Area not available in PESI transformer " +  area.getTitleCache());
464
				return false;
465
			}
466
        }
467
		return true;
468
	}
469

    
470
	private boolean isPesiNote(DescriptionElementBase element) {
471
		return (getNoteCategoryFk(element) != null);
472
	}
473

    
474
	private boolean isAdditionalTaxonSource(DescriptionElementBase element) {
475
		Feature feature = element.getFeature();
476
		if (feature == null){
477
			return false;
478
		}
479
		return (feature.equals(Feature.CITATION()) || feature.equals(Feature.ADDITIONAL_PUBLICATION()));
480
	}
481

    
482
	private boolean isOccurrence(DescriptionElementBase element) {
483
		Feature feature = element.getFeature();
484
		if (element.isInstanceOf(Distribution.class)){
485
		    if (!Feature.DISTRIBUTION().equals(feature)){
486
		        logger.warn("Description element has class 'Distribution' but has no feature 'Distribution'");
487
		    }
488
		    return true;
489
		}else if (Feature.DISTRIBUTION().equals(feature)){
490
		    logger.debug("Description element has feature Distribtuion but is not of class 'Distribution'");
491
            return false;
492
		}else{
493
			return false;
494
		}
495
	}
496

    
497
	private boolean isCommonName(DescriptionElementBase element) {
498
		Feature feature = element.getFeature();
499
		if (feature == null){
500
			return false;
501
		}
502
		return (feature.equals(Feature.COMMON_NAME()));
503
	}
504

    
505
	//PHASE 02: Name extensions
506
	private boolean doPhase02(PesiExportState state) {
507
		TransactionStatus txStatus;
508
		boolean success =  true;
509

    
510
		// Get the limit for objects to save within a single transaction.
511
		//int limit = state.getConfig().getLimitSave();
512
		int limit = 2000;
513
		txStatus = startTransaction(true);
514
		ExtensionType taxCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtTaxComment);
515
		ExtensionType fauCommentExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtFauComment);
516
		ExtensionType fauExtraCodesExtensionType = (ExtensionType)getTermService().find(PesiTransformer.uuidExtFauExtraCodes);
517
		List<TaxonName> taxonNameList;
518

    
519
		int count = 0;
520
		int pastCount = 0;
521
		Connection connection = state.getConfig().getDestination().getConnection();
522
		if (logger.isDebugEnabled()) {
523
            logger.info("Started new transaction. Fetching some " + parentPluralString + " first (max: " + limit + ") ...");
524
        }
525
		logger.warn("TODO handle extensions on taxon level, not name level (");
526
		while ((taxonNameList = getNameService().list(null, limit, count, null, null)).size() > 0) {
527

    
528
			if(logger.isDebugEnabled()) {
529
                logger.info("Fetched " + taxonNameList.size() + " names. Exporting...");
530
            }
531
			for (TaxonName taxonName : taxonNameList) {
532
				Set<Extension> extensions = taxonName.getExtensions();
533
				for (Extension extension : extensions) {
534
					if (extension.getType().equals(taxCommentExtensionType)) {
535
						String taxComment = extension.getValue();
536
						invokeNotes(taxComment,
537
								PesiTransformer.getNoteCategoryFk(PesiTransformer.uuidExtTaxComment),
538
								PesiTransformer.getNoteCategoryCache(PesiTransformer.uuidExtTaxComment),
539
								null, null, getTaxonKey(taxonName, state),connection);
540
					} else if (extension.getType().equals(fauCommentExtensionType)) {
541
						String fauComment = extension.getValue();
542
						invokeNotes(fauComment,
543
								PesiTransformer.getNoteCategoryFk(PesiTransformer.uuidExtFauComment),
544
								PesiTransformer.getNoteCategoryCache(PesiTransformer.uuidExtFauComment),
545
								null, null, getTaxonKey(taxonName, state),connection);
546
					} else if (extension.getType().equals(fauExtraCodesExtensionType)) {
547
						String fauExtraCodes = extension.getValue();
548
						invokeNotes(fauExtraCodes,
549
								PesiTransformer.getNoteCategoryFk(PesiTransformer.uuidExtFauExtraCodes),
550
								PesiTransformer.getNoteCategoryCache(PesiTransformer.uuidExtFauExtraCodes),
551
								null, null, getTaxonKey(taxonName, state),connection);
552
					}
553
				}
554

    
555
				doCount(count++, modCount, parentPluralString);
556
			}
557

    
558
			// Commit transaction
559
			commitTransaction(txStatus);
560
			logger.debug("Committed transaction.");
561
			logger.info("Exported " + (count - pastCount) + " names. Total: " + count + " (Phase 02)");
562
			pastCount = count;
563

    
564
			// Start transaction
565
			txStatus = startTransaction(true);
566
			if (logger.isDebugEnabled()) {
567
                logger.info("Started new transaction. Fetching some names first (max: " + limit + ") ...");
568
            }
569
		}
570
		// Commit transaction
571
		commitTransaction(txStatus);
572
		logger.debug("Committed transaction.");
573
		return success;
574
	}
575

    
576
	private void invokeNotes(String note, Integer noteCategoryFk,
577
			String noteCategoryCache, Integer languageFk, String languageCache,
578
			Integer taxonFk, Connection connection) {
579

    
580
	    String notesSql = "UPDATE Note SET Note_1 = ?, NoteCategoryFk = ?, NoteCategoryCache = ?, LanguageFk = ?, LanguageCache = ? WHERE TaxonFk = ?";
581
		try {
582
			PreparedStatement notesStmt = connection.prepareStatement(notesSql);
583

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

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

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

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

    
608
			if (languageCache != null) {
609
				notesStmt.setString(5, languageCache);
610
			} else {
611
				notesStmt.setObject(5, null);
612
			}
613

    
614
			if (taxonFk != null) {
615
				notesStmt.setInt(6, taxonFk);
616
			} else {
617
				notesStmt.setObject(6, null);
618
			}
619

    
620
			notesStmt.executeUpdate();
621
		} catch (SQLException e) {
622
			logger.error("Note could not be created: " + note);
623
			e.printStackTrace();
624
		}
625
	}
626

    
627
	/**
628
	 * Deletes all entries of database tables related to <code>Note</code>.
629
	 * @param state The PesiExportState
630
	 * @return Whether the delete operation was successful or not.
631
	 */
632
	protected boolean doDelete(PesiExportState state) {
633
	    Source destination = state.getConfig().getDestination();
634

    
635
		// Clear NoteSource
636
		String sql = "DELETE FROM NoteSource";
637
		destination.update(sql);
638
		// Clear Note
639
		sql = "DELETE FROM Note "; // + dbNoteTableName;
640
		destination.update(sql);
641

    
642
	    // Clear OccurrenceSource
643
        sql = "DELETE FROM OccurrenceSource ";
644
        destination.update(sql);
645
        // Clear Occurrence
646
        sql = "DELETE FROM Occurrence ";
647
        destination.update(sql);
648

    
649
        // Clear Image
650
        sql = "DELETE FROM Image ";
651
        destination.update(sql);
652

    
653
        // Clear CommonName
654
        sql = "DELETE FROM CommonNameSource ";
655
        destination.update(sql);
656
        sql = "DELETE FROM CommonName ";
657
        destination.update(sql);
658

    
659
        // Clear AdditionalTaxonSource
660
        sql = "DELETE FROM AdditionalTaxonSource WHERE SourceFk >= 2000000 ";
661
        destination.update(sql);
662

    
663
        // Clear Sources for AdditionalTaxonSource
664
        sql = "DELETE FROM Source WHERE SourceId >= 2000000 ";
665
        destination.update(sql);
666

    
667
		return true;
668
	}
669

    
670
	/**
671
	 * Returns the <code>Note_2</code> attribute.
672
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
673
	 * @return The <code>Note_2</code> attribute.
674
	 * @see MethodMapper
675
	 */
676
	@SuppressWarnings("unused") //used for mapper
677
	private static String getNote_2(DescriptionElementBase element) {
678
		//E+M map links -> medium
679
		if (element.getFeature() != null && element.getFeature().getUuid().equals(BerlinModelTransformer.uuidFeatureMaps)){
680
			String text = CdmBase.deproxy(element, TextData.class).getText(Language.ENGLISH());
681
			if (text.contains("medium")){
682
				return "medium";
683
			}
684
		}
685
		return null;
686
	}
687

    
688
	/**
689
	 * Returns the <code>NoteCategoryFk</code> attribute.
690
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
691
	 * @return The <code>NoteCategoryFk</code> attribute.
692
	 * @see MethodMapper
693
	 */
694
	private static Integer getNoteCategoryFk(DescriptionElementBase descriptionElement) {
695
		Integer result = null;
696
		result = PesiTransformer.feature2NoteCategoryFk(descriptionElement.getFeature());
697
		//TODO decide where to handle them best (configurator, transformer, single method, ...)
698
		if (excludedNoteCategories.contains(result)){
699
			result = null;
700
		}
701
		return result;
702
	}
703

    
704
	/**
705
	 * Returns the <code>NoteCategoryCache</code> attribute.
706
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
707
	 * @return The <code>NoteCategoryCache</code> attribute.
708
	 * @see MethodMapper
709
	 */
710
	@SuppressWarnings("unused")
711
	private static String getNoteCategoryCache(DescriptionElementBase descriptionElement, PesiExportState state) {
712
		return state.getTransformer().getCacheByFeature(descriptionElement.getFeature());
713
	}
714

    
715
	/**
716
	 * Returns the <code>LanguageFk</code> attribute.
717
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
718
	 * @return The <code>LanguageFk</code> attribute.
719
	 * @see MethodMapper
720
	 */
721
	@SuppressWarnings("unused")
722
	private static Integer getLanguageFk(DescriptionElementBase descriptionElement) {
723
		Language language = getLanguage(descriptionElement);
724

    
725
		return PesiTransformer.language2LanguageId(language);
726
	}
727

    
728
	/**
729
	 * Returns the <code>LanguageCache</code> attribute.
730
	 * @param descriptionElement The {@link DescriptionElementBase DescriptionElement}.
731
	 * @return The <code>LanguageCache</code> attribute.
732
	 * @throws UndefinedTransformerMethodException
733
	 * @see MethodMapper
734
	 */
735
	@SuppressWarnings("unused")
736
	private static String getLanguageCache(DescriptionElementBase descriptionElement, PesiExportState state) throws UndefinedTransformerMethodException {
737
		Language language = getLanguage(descriptionElement);
738
		return state.getTransformer().getCacheByLanguage(language);
739
	}
740

    
741
	private static Language getLanguage(DescriptionElementBase descriptionElement) {
742
		Language language = null;
743

    
744
		Map<Language, LanguageString> multilanguageText = null;
745
		if (descriptionElement.isInstanceOf(CommonTaxonName.class)) {
746
			CommonTaxonName commonTaxonName = CdmBase.deproxy(descriptionElement, CommonTaxonName.class);
747
			language = commonTaxonName.getLanguage();
748
		} else if (descriptionElement.isInstanceOf(TextData.class)) {
749
			TextData textData = CdmBase.deproxy(descriptionElement, TextData.class);
750
			multilanguageText = textData.getMultilanguageText();
751
		} else if (descriptionElement.isInstanceOf(IndividualsAssociation.class)) {
752
			IndividualsAssociation individualsAssociation = CdmBase.deproxy(descriptionElement, IndividualsAssociation.class);
753
			multilanguageText = individualsAssociation.getDescription();
754
		} else if (descriptionElement.isInstanceOf(TaxonInteraction.class)) {
755
			TaxonInteraction taxonInteraction = CdmBase.deproxy(descriptionElement, TaxonInteraction.class);
756
			multilanguageText = taxonInteraction.getDescription();
757
		} else {
758
			logger.debug("Given descriptionElement does not support languages. Hence LanguageCache could not be determined: " + descriptionElement.getUuid());
759
		}
760

    
761
		if (multilanguageText != null) {
762
			Set<Language> languages = multilanguageText.keySet();
763

    
764
			// TODO: Think of something more sophisticated than this
765
			if (languages.size() > 0) {
766
				language = languages.iterator().next();
767
			}
768
			if (languages.size() > 1){
769
				logger.warn("There is more than 1 language for a given description (" + descriptionElement.getClass().getSimpleName() + "):" + descriptionElement.getUuid());
770
			}
771
		}
772
		return language;
773
	}
774

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

    
802

    
803
	/**
804
	 * @param state The {@link DbExportStateBase DbExportState}.
805
	 * @return
806
	 */
807
	@SuppressWarnings("unused")  //used by mapper
808
	private static Integer getTaxonFk(DescriptionElementBase deb, PesiExportState state) {
809
		TaxonBase<?> entity = state.getCurrentTaxon();
810
		return state.getDbId(entity);
811
	}
812

    
813
	/**
814
	 * Returns the TaxonFk for a given TaxonName.
815
	 * @param taxonName The {@link TaxonNameBase TaxonName}.
816
	 * @param state The {@link DbExportStateBase DbExportState}.
817
	 * @return
818
	 */
819
	private static Integer getTaxonKey(TaxonName taxonName, DbExportStateBase<?, PesiTransformer> state) {
820
		return state.getDbId(taxonName);
821
	}
822

    
823
	/**
824
	 * Returns the <code>FullName</code> attribute.
825
	 * @param taxonName The {@link NonViralName NonViralName}.
826
	 * @return The <code>FullName</code> attribute.
827
	 * @see MethodMapper
828
	 */
829
	@SuppressWarnings("unused")
830
	private static String getTaxonFullNameCache(DescriptionElementBase deb, PesiExportState state) {
831

    
832
		TaxonBase<?> taxon =  state.getCurrentTaxon();
833
		TaxonName taxonName = taxon.getName();
834
		TaxonName nvn = CdmBase.deproxy(taxonName);
835
		String result = getCacheStrategy(nvn).getTitleCache(nvn);
836
		return result;
837
	}
838

    
839
    @SuppressWarnings("unused")  //used by mapper
840
    private static Integer getCurrentTaxonFk(Media media, PesiExportState state) {
841
        return state.getDbId(state.getCurrentTaxon());
842
    }
843

    
844
    @SuppressWarnings("unused")  //used by mapper
845
    private static String getMediaThumb(Media media) {
846
        String startsWith = "http://images.vliz.be/thumbs/";
847
        String result = null;
848
        for (MediaRepresentation rep : media.getRepresentations()){
849
            for (MediaRepresentationPart part : rep.getParts()){
850
                String strUrl = part.getUri().toString();
851
                if (strUrl.startsWith(startsWith)){
852
                    result = part.getUri().toString();
853
                }
854
            }
855
        }
856
        return result;
857
    }
858

    
859
    @SuppressWarnings("unused")  //used by mapper
860
    private static String getMediaUrl(Media media) {
861
        String startsWith = "http://www.marbef.org/data/aphia.php?p=image&pic=";
862
        String result = null;
863
        for (MediaRepresentation rep : media.getRepresentations()){
864
            for (MediaRepresentationPart part : rep.getParts()){
865
                String strUrl = part.getUri().toString();
866
                if (strUrl.startsWith(startsWith)){
867
                    result = part.getUri().toString();
868
                }
869
            }
870
        }
871
        return result;
872
    }
873

    
874
//******************************* MAPPINGS ********************************************
875

    
876
	/**
877
	 * Returns the CDM to PESI specific export mappings for PESI notes.
878
	 * @return The {@link PesiExportMapping PesiExportMapping}.
879
	 */
880
	private PesiExportMapping getNotesMapping() {
881
		PesiExportMapping mapping = new PesiExportMapping(dbNoteTableName);
882

    
883
		mapping.addMapper(IdMapper.NewInstance("NoteId"));
884
		mapping.addMapper(DbTextDataMapper.NewInstance(Language.ENGLISH(), "Note_1"));
885
		//TODO
886
		mapping.addMapper(MethodMapper.NewInstance("Note_2", this, standardMethodParameter));
887
		mapping.addMapper(MethodMapper.NewInstance("NoteCategoryFk", this, standardMethodParameter ));
888

    
889
		mapping.addMapper(MethodMapper.NewInstance("NoteCategoryCache", this, standardMethodParameter, PesiExportState.class ));
890
		mapping.addMapper(MethodMapper.NewInstance("LanguageFk", this));
891
		mapping.addMapper(MethodMapper.NewInstance("LanguageCache", this, standardMethodParameter, PesiExportState.class));
892

    
893
//		mapping.addMapper(MethodMapper.NewInstance("Region", this));
894
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
895
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
896
		mapping.addCollectionMapping(getNoteSourceMapping());
897
		return mapping;
898
	}
899

    
900
	private CollectionExportMapping<PesiExportState, PesiExportConfigurator,PesiTransformer> getNoteSourceMapping() {
901
		String tableName = "NoteSource";
902
		String collectionAttribute = "sources";
903
		IdMapper parentMapper = IdMapper.NewInstance("NoteFk");
904
		@SuppressWarnings("unchecked")
905
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
906
                = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
907
		mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource", "Sources with idInSource currently handle data lineage"));
908
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
909
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
910
		mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
911
		return mapping;
912
	}
913

    
914
	/**
915
	 * Returns the CDM to PESI specific export mappings for occurrences.
916
	 * @return The {@link PesiExportMapping PesiExportMapping}.
917
	 */
918
	private PesiExportMapping getOccurrenceMapping() {
919
		PesiExportMapping mapping = new PesiExportMapping(dbOccurrenceTableName);
920

    
921
		mapping.addMapper(IdMapper.NewInstance("OccurrenceId"));
922
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
923
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("TaxonFullNameCache", true, true, null));
924

    
925
		mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaFk", ! IS_CACHE));
926
		mapping.addMapper(DbAreaMapper.NewInstance(Distribution.class, "Area", "AreaNameCache", IS_CACHE));
927
		mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusFk", ! IS_CACHE));
928
		mapping.addMapper(DbDistributionStatusMapper.NewInstance("OccurrenceStatusCache", IS_CACHE));
929

    
930
//		Use OccurrenceSource table instead
931
		mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceFk", "Use OccurrenceSource table for sources instead"));
932
		mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceNameCache", "Use OccurrenceSource table for sources instead"));
933

    
934
		mapping.addMapper(DbAnnotationMapper.NewExludedInstance(getLastActionAnnotationTypes(), "Notes"));
935
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
936
		mapping.addCollectionMapping(getOccurrenceSourceMapping());
937

    
938
		return mapping;
939
	}
940

    
941
	private CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> getOccurrenceSourceMapping() {
942
		String tableName = "OccurrenceSource";
943
		String collectionAttribute = "sources";
944
		IdMapper parentMapper = IdMapper.NewInstance("OccurrenceFk");
945
		@SuppressWarnings("unchecked")
946
        CollectionExportMapping<PesiExportState, PesiExportConfigurator, PesiTransformer> mapping
947
		        = CollectionExportMapping.NewInstance(tableName, collectionAttribute, parentMapper);
948
		mapping.addMapper(DbSimpleFilterMapper.NewSingleNullAttributeInstance("idInSource",
949
		        "Sources with idInSource currently handle data lineage"));
950
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceFk"));
951
		mapping.addMapper(DbObjectMapper.NewInstance("Citation", "SourceNameCache", IS_CACHE));
952
		mapping.addMapper(DbStringMapper.NewInstance("CitationMicroReference", "SourceDetail"));
953
        mapping.addMapper(DbOriginalNameMapper.NewInstance("OldTaxonName", IS_CACHE, null));
954

    
955
		return mapping;
956
	}
957

    
958
	/**
959
	 * Returns the CDM to PESI specific export mappings for additional taxon sources to create a new
960
	 * source for the additional taxon source
961
	 * @see #{@link PesiDescriptionExport#getAdditionalTaxonSourceMapping()}
962
	 * @return The {@link PesiExportMapping PesiExportMapping}.
963
	 */
964
	private PesiExportMapping getAddTaxonSourceSourceMapping() {
965
		PesiExportMapping sourceMapping = new PesiExportMapping(PesiSourceExport.dbTableName);
966

    
967
		sourceMapping.addMapper(IdMapper.NewInstance("SourceId"));
968
		sourceMapping.addMapper(DbConstantMapper.NewInstance("SourceCategoryFk", Types.INTEGER, PesiTransformer.REF_UNRESOLVED));
969
		sourceMapping.addMapper(DbConstantMapper.NewInstance("SourceCategoryCache", Types.VARCHAR, PesiTransformer.REF_STR_UNRESOLVED));
970

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

    
973
		sourceMapping.addMapper(DbTextDataMapper.NewInstance(Language.ENGLISH(), "NomRefCache"));
974

    
975
		return sourceMapping;
976
	}
977

    
978
	/**
979
	 * Returns the CDM to PESI specific export mappings for additional taxon sources.
980
	 * @see #{@link PesiDescriptionExport#getAddTaxonSourceSourceMapping()}
981
	 * @return The {@link PesiExportMapping PesiExportMapping}.
982
	 */
983
	private PesiExportMapping getAdditionalTaxonSourceMapping() {
984

    
985
		PesiExportMapping mapping = new PesiExportMapping(dbAdditionalSourceTableName);
986

    
987
		mapping.addMapper(MethodMapper.NewInstance("TaxonFk", this, DescriptionElementBase.class, PesiExportState.class));
988

    
989
		mapping.addMapper(IdMapper.NewInstance("SourceFk"));
990
		mapping.addMapper(DbTextDataMapper.NewInstance(Language.ENGLISH(), "SourceNameCache"));
991

    
992
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseFk", Types.INTEGER, PesiTransformer.NOMENCLATURAL_REFERENCE));
993
		mapping.addMapper(DbConstantMapper.NewInstance("SourceUseCache", Types.VARCHAR, PesiTransformer.STR_NOMENCLATURAL_REFERENCE));
994

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

    
997
		return mapping;
998
	}
999

    
1000
	/**
1001
	 * Returns the CDM to PESI specific export mappings for common names.
1002
	 * @return The {@link PesiExportMapping PesiExportMapping}.
1003
	 */
1004
	private PesiExportMapping getCommonNamesMapping() {
1005
		PesiExportMapping mapping = new PesiExportMapping(dbVernacularTableName);
1006

    
1007
		mapping.addMapper(IdMapper.NewInstance("CommonNameId"));
1008
		mapping.addMapper(DbDescriptionElementTaxonMapper.NewInstance("taxonFk"));
1009

    
1010
		mapping.addMapper(DbStringMapper.NewInstance("Name", "CommonName"));
1011
		mapping.addMapper(DbAreaMapper.NewInstance(CommonTaxonName.class, "Area", "Region", IS_CACHE));
1012

    
1013
		mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageFk", ! IS_CACHE));
1014
		mapping.addMapper(DbLanguageMapper.NewInstance(CommonTaxonName.class, "Language", "LanguageCache", IS_CACHE));
1015

    
1016
//      Use OccurrenceSource table instead
1017
        mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceFk", "Use CommonNameSource table for sources instead"));
1018
        mapping.addMapper(DbExportIgnoreMapper.NewInstance("SourceNameCache", "Use CommonNameSource table for sources instead"));
1019
        //OLD
1020
//		mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceFk", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , ! IS_CACHE));
1021
//		mapping.addMapper(DbSingleSourceMapper.NewInstance("SourceNameCache", of ( DbSingleSourceMapper.EXCLUDE.WITH_ID) , IS_CACHE));
1022

    
1023
		mapping.addMapper(ExpertsAndLastActionMapper.NewInstance());
1024
	    mapping.addCollectionMapping(getCommonNameSourceMapping());
1025
		return mapping;
1026
	}
1027

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

    
1042
        return mapping;
1043
    }
1044

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

    
1053
    @Override
1054
    protected boolean doCheck(PesiExportState state) {
1055
        boolean result = true;
1056
        return result;
1057
    }
1058

    
1059
    @Override
1060
    protected boolean isIgnore(PesiExportState state) {
1061
        return ! state.getConfig().isDoDescription();
1062
    }
1063
}
(4-4/14)