Project

General

Profile

Download (18.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 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.csv.redlist.demo;
10

    
11
import java.io.ByteArrayOutputStream;
12
import java.io.FileNotFoundException;
13
import java.io.PrintWriter;
14
import java.util.ArrayList;
15
import java.util.Collections;
16
import java.util.Comparator;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Set;
20
import java.util.UUID;
21

    
22
import org.apache.commons.lang.StringUtils;
23
import org.apache.logging.log4j.LogManager;
24
import org.apache.logging.log4j.Logger;
25
import org.springframework.stereotype.Component;
26
import org.springframework.transaction.TransactionStatus;
27

    
28
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
29
import eu.etaxonomy.cdm.model.common.CdmBase;
30
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
31
import eu.etaxonomy.cdm.model.common.Language;
32
import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
33
import eu.etaxonomy.cdm.model.description.CategoricalData;
34
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
35
import eu.etaxonomy.cdm.model.description.Distribution;
36
import eu.etaxonomy.cdm.model.description.Feature;
37
import eu.etaxonomy.cdm.model.description.State;
38
import eu.etaxonomy.cdm.model.description.TaxonDescription;
39
import eu.etaxonomy.cdm.model.description.TextData;
40
import eu.etaxonomy.cdm.model.location.NamedArea;
41
import eu.etaxonomy.cdm.model.name.INonViralName;
42
import eu.etaxonomy.cdm.model.reference.Reference;
43
import eu.etaxonomy.cdm.model.taxon.Classification;
44
import eu.etaxonomy.cdm.model.taxon.Synonym;
45
import eu.etaxonomy.cdm.model.taxon.SynonymType;
46
import eu.etaxonomy.cdm.model.taxon.Taxon;
47
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
48
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
49
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
50
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
51

    
52
/**
53
 * @author a.oppermann
54
 * @since 18.10.2012
55
 */
56
@Component
57
public class CsvDemoExport extends CsvDemoBase {
58

    
59
    private static final long serialVersionUID = 8265935377927091897L;
60

    
61
    private static final Logger logger = LogManager.getLogger(CsvDemoExport.class);
62

    
63
	private static final String ROW_TYPE = "http://rs.tdwg.org/dwc/terms/Taxon";
64
	private static final String fileName = "RedlistCoreTax.csv";
65

    
66
	public CsvDemoExport() {
67
		super();
68
		this.ioName = this.getClass().getSimpleName();
69
	}
70

    
71

    
72
	/** Retrieves data from a CDM DB and serializes them CDM to CSV.
73
	 * Starts with root taxa and traverses the classification to retrieve
74
	 * children taxa, synonyms, relationships, descriptive data, red list
75
	 * status (features).
76
	 * Taxa that are not part of the classification are not found.
77
	 *
78
	 * @param exImpConfig
79
	 * @param dbname
80
	 * @param filename
81
	 */
82
	@Override
83
	protected void doInvoke(CsvDemoExportState state){
84
	    CsvDemoExportConfigurator config = state.getConfig();
85
	    TransactionStatus txStatus = startTransaction(true);
86

    
87
	    List<NamedArea> selectedAreas = config.getNamedAreas();
88
	    Set<Classification> classificationSet = assembleClassificationSet(config);
89

    
90
	    IProgressMonitor progressMonitor = null;
91
	    if(config.getProgressMonitor() != null) {
92
	        progressMonitor = config.getProgressMonitor();
93
	    }
94
	    PrintWriter writer = null;
95
	    try {
96
	        //json/xml result list
97
            List<CsvDemoRecord> recordList = null;
98
            if(config.getRecordList() != null){
99
                recordList = config.getRecordList();
100
                performJsonXMLPagination(state, config, txStatus, classificationSet, recordList);
101
            }
102

    
103
            try {
104
                switch(config.getTarget()) {
105
                case FILE:
106
                    if(!config.getDestination().isDirectory()){
107
                        writer = new PrintWriter(config.getDestination());
108
                    }
109
                    break;
110
                case EXPORT_DATA:
111
                    exportStream = new ByteArrayOutputStream();
112
                    writer = new PrintWriter(exportStream);
113
                    break;
114
                default :
115
                    break;
116
                }
117
                if(writer != null) {
118
                    performCSVExport(state, config, txStatus, classificationSet, progressMonitor, writer);
119
                }
120

    
121
            } catch (FileNotFoundException e) {
122
                e.printStackTrace();
123
            }
124

    
125
	    } catch (ClassCastException e) {
126
	        e.printStackTrace();
127
	    }
128
	    finally{
129
	        if (exportStream != null){
130
	            state.getResult().addExportData(getByteArray());
131
	        }
132
	        if(writer != null){
133
	            writer.close();
134
	        }
135
	        this.clearExistingRecordIds();
136
	    }
137

    
138
	    return;
139
	}
140

    
141
    private void performJsonXMLPagination(CsvDemoExportState state, CsvDemoExportConfigurator config,
142
            TransactionStatus txStatus, Set<Classification> classificationSet, List<CsvDemoRecord> recordList) {
143

    
144
        Classification classification = null;
145
        for(Classification c : classificationSet){
146
            classification = c;
147
            //this sets the total amount of records for pagination
148
            config.setTaxonNodeListSize(getTaxonNodeService().countAllNodesForClassification(c));
149
        }
150
        //calculate pagination
151
        int start = config.getPageSize() * config.getPageNumber();
152
        List<TaxonNode> result = getTaxonNodeService().listAllNodesForClassification(classification, start, config.getPageSize());
153

    
154
        for (TaxonNode node : result){
155
            Taxon taxon = CdmBase.deproxy(node.getTaxon(), Taxon.class);
156
            CsvDemoRecord record = assembleRecord(state);
157
            INonViralName name = taxon.getName();
158
            config.setClassificationTitleCache(classification.getTitleCache());
159
            if (! this.recordExists(taxon)){
160
                handleTaxonBase(record, taxon, name, classification, null, false, false, config, node);
161
                recordList.add(record);
162
                this.addExistingRecord(taxon);
163
            }
164
        }
165
        commitTransaction(txStatus);
166
    }
167

    
168
	private void performCSVExport(CsvDemoExportState state, CsvDemoExportConfigurator config,
169
	        TransactionStatus txStatus, Set<Classification> classificationSet, IProgressMonitor progressMonitor,
170
	        PrintWriter writer) {
171
	    //obtain chuncks of taxonNodes
172
	    int totalWork = 0;
173
	    int work = 0;
174
	    int limit = 500;
175
	    int end = 500;
176
	    int start = 0;
177

    
178
	    //TODO: Questionable if this information is really necessary, with respect to memory usage
179
	    Classification classification = null;
180
	    for(Classification c : classificationSet){
181
	    	classification = c;
182
	    	totalWork = getTaxonNodeService().countAllNodesForClassification(c);
183

    
184

    
185
	    	if(progressMonitor != null) {
186
	    		progressMonitor.beginTask("", totalWork);
187
	    	}
188
	    	List<TaxonNode> result = new ArrayList<>();
189
	    	int totalNodes = getTaxonNodeService().count(TaxonNode.class);
190

    
191
	    	for(int i = 0 ; i < totalNodes; i++){
192

    
193
	    		//geographical Filter
194
	    		//	     List<TaxonNode> taxonNodes =  handleGeographicalFilter(state, classificationSet, config, limit, start);
195

    
196
	    		result = getTaxonNodeService().listAllNodesForClassification(classification, start, limit);
197

    
198
	    		logger.info(result.size());
199

    
200

    
201
	    		for (TaxonNode node : result){
202
	    			Taxon taxon = CdmBase.deproxy(node.getTaxon(), Taxon.class);
203
	    			CsvDemoRecord record = assembleRecord(state);
204
	    			INonViralName name = taxon.getName();
205
	    			//	                Classification classification = node.getClassification();
206
	    			config.setClassificationTitleCache(classification.getTitleCache());
207
	    			if (! this.recordExists(taxon)){
208

    
209
	    				handleTaxonBase(record, taxon, name, classification, null, false, false, config, node);
210
	    				//if(config.getDestination() != null){
211
	    					record.write(writer);
212
	    				//}
213
	    				this.addExistingRecord(taxon);
214
	    			}
215
	    			//misapplied names
216
	    			//handleMisapplication(taxon, writer, classification, record, config, node);
217

    
218
	    			if(progressMonitor !=null) {
219
	    				if(work < totalWork-1) {
220
	    					progressMonitor.worked(1);
221
	    				}
222
	    				work++;
223
	    			}
224
	    		}
225
	    		if(writer != null){
226
	    			writer.flush();
227
	    			commitTransaction(txStatus);
228
	    			txStatus = startTransaction(true);
229
	    		}
230
	    		//get next 1000 results
231
	    		if(result.size()%limit == 0){
232
	    			//increase only once to avoid same row
233
	    			if(i==0){
234
	    				start++;
235
	    			}
236
	    			start = start + limit;
237
	    			end = end + limit;
238
	    			result = null;
239
	    		}else{
240
	    			break;
241
	    		}
242
	    	}
243
	    }
244
	}
245

    
246
    //TODO: Exception handling
247
	/**
248
	 *
249
	 * @param config
250
	 */
251
	protected Set<Classification> assembleClassificationSet(CsvDemoExportConfigurator config){
252
		if(config != null){
253
			Set<UUID> classificationUuidSet = config.getClassificationUuids();
254
			List<Classification> classificationList = getClassificationService().find(classificationUuidSet);
255
			Set<Classification> classificationSet = new HashSet<>();
256
			classificationSet.addAll(classificationList);
257
			return classificationSet;
258
		}
259
		return null;
260
	}
261

    
262
	//TODO: Exception handling
263
	/**
264
	 * @param state
265
	 */
266
	private CsvDemoRecord assembleRecord(CsvDemoExportState state) {
267
		if(state!=null){
268
			CsvDemoExportConfigurator config = state.getConfig();
269
			CsvDemoMetaDataRecord metaRecord = new CsvDemoMetaDataRecord(true, fileName, ROW_TYPE);
270
			state.addMetaRecord(metaRecord);
271
			CsvDemoRecord record = new CsvDemoRecord(metaRecord, config);
272
			return record;
273
		}
274
		return null;
275
	}
276

    
277
	/**
278
	 * handles the information record for the actual {@link Taxon} including {@link Classification classification}, Taxon Name, Taxon ID,
279
	 * Taxon Status, Synonyms, {@link Feature features} data
280
	 *
281
	 * @param record the concrete information record
282
	 */
283
	private void handleTaxonBase(CsvDemoRecord record, TaxonBase<?> taxonBase,
284
			INonViralName name, Classification classification,
285
			RelationshipTermBase<?> relType, boolean isProParte, boolean isPartial,
286
			CsvDemoExportConfigurator config, TaxonNode node) {
287

    
288
		Taxon taxon = (Taxon) taxonBase;
289
		List<Feature> features = config.getFeatures();
290
		if(config.getDestination() != null){
291
		    record.setHeadLinePrinted(config.isHasHeaderLines());
292
		    if(config.isRedlistFeatures()){
293
		        if(features != null){
294
		            record.setPrintFeatures(features);
295
		        }
296
		    }
297
		    config.setHasHeaderLines(false);
298
		}
299
		if(config.isClassification()){
300
			record.setDatasetName(classification.getTitleCache());
301
		}
302
		if(config.isTaxonName()){
303
			record.setScientificName(name.getNameCache());
304
		}
305
		if(config.isTaxonNameID()){
306
			record.setScientificNameId(name.getUuid().toString());
307
		}
308
		if(config.isAuthor()){
309
			String authorshipCache = name.getAuthorshipCache();
310
			if(authorshipCache == null){
311
				authorshipCache = "";
312
			}
313
			record.setAuthorName(authorshipCache);
314
		}
315
		if(config.isRank()){
316
			String rank;
317
			if(taxon.getName().getRank() == null){
318
				rank = "";
319
			}else{
320
				rank = taxon.getName().getRank().toString();
321
			}
322
			record.setRank(rank);
323
		}
324
		if(config.isTaxonStatus()){
325
			handleTaxonomicStatus(record, name, relType, isProParte, isPartial);
326
		}
327
		if(config.isAcceptedName()){
328
			//TODO write routine for accepted Name
329
		}
330
		if(config.isTaxonConceptID()){
331
			UUID taxonUuid = taxonBase.getUuid();
332
			if(taxonUuid == null){
333
				taxonUuid = UUID.fromString("");
334
			}
335
			record.setTaxonConceptID(taxonUuid.toString());
336
		}
337
		if(config.isParentID()){
338
			String parentUUID;
339
			if(node.getParent().getTaxon() == null){
340
				parentUUID = "";
341
			}else{
342
				parentUUID = node.getParent().getTaxon().getUuid().toString();
343
			}
344
			record.setParentUUID(parentUUID);
345
		}
346
		if(config.isLastChange()){
347
			String lastChange;
348
			if(taxon.getUpdated() == null){
349
				lastChange = "";
350
			}else{
351
				lastChange = taxon.getUpdated().toString();
352
			}
353
			record.setLastChange(lastChange);
354
		}
355
		if(config.isSynonyms()){
356
			handleSynonyms(record,taxon);
357
		}
358
		if(config.isDistributions()){
359
			handleDiscriptionData(record, taxon);
360
		}
361
		if(config.isRedlistFeatures()){
362
			if(features!= null) {
363

    
364
				List<List<String>> featureCells = new ArrayList<>(features.size());
365
				for(int i = 0; i < features.size(); i++) {
366
					featureCells.add(new ArrayList<>());
367
				}
368
				handleRelatedRedlistStatus(record, taxon, false, featureCells, features);
369
				handleRelatedRedlistStatus(record, taxon, true, featureCells, features);
370
			}
371
		}
372

    
373
		if(config.isExternalID()){
374
			Set<IdentifiableSource> sources = taxonBase.getSources();
375
			for(IdentifiableSource source:sources){
376
				Reference citation = source.getCitation();
377
				/*
378
				 * TODO: handle this more generic.
379
				 * see ticket #4040
380
				 *
381
				 */
382
				if(citation.getId() == 22){
383
					String idInSource = source.getIdInSource();
384
					if(idInSource == null){
385
						idInSource = "";
386
					}
387
					record.setExternalID(idInSource);
388

    
389
				}
390
			}
391
		}
392
	}
393

    
394
	private void handleTaxonomicStatus(
395
			CsvDemoRecord record,
396
			INonViralName name,
397
			RelationshipTermBase<?> type,
398
			boolean isProParte,
399
			boolean isPartial) {
400
		if (type == null && name.getNameType()!= null && name.getNameType().acceptedTaxonStatusLabel() != null){
401
			String acceptedTaxonStatusLabel = name.getNameType().acceptedTaxonStatusLabel();
402
			if(StringUtils.isEmpty(acceptedTaxonStatusLabel)){
403
				acceptedTaxonStatusLabel="";
404
			}
405
			record.setTaxonomicStatus(acceptedTaxonStatusLabel);
406
		}else if(name.getNameType() != null && name.getNameType().synonymStatusLabel() != null){
407
			String status = name.getNameType().synonymStatusLabel();
408
			if (type.equals(SynonymType.HETEROTYPIC_SYNONYM_OF())){
409
				status = "heterotypicSynonym";
410
			}else if(type.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
411
				status = "homotypicSynonym";
412
			}else if(type.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
413
				status = "misapplied";
414
			}else if(type.equals(TaxonRelationshipType.PRO_PARTE_MISAPPLIED_NAME_FOR())){
415
                status = "proParteMisapplied";
416
            }
417
			if (isProParte){
418
				status = "proParteSynonym";
419
			}else if (isPartial){
420
				String message = "Partial synonym is not part of the gbif toxonomic status vocabulary";
421
				logger.warn(message);
422
				status = "partialSynonym";
423
			}
424

    
425
			record.setTaxonomicStatus(status);
426
		}
427
	}
428

    
429
	/**
430
	 * This method concatenates several synonyms in a list.
431
	 */
432
	private void handleSynonyms(CsvDemoRecord record, Taxon taxon) {
433

    
434
		Set<Synonym> synonyms = taxon.getSynonyms();
435
		ArrayList<String> synonymLabels = new ArrayList<>();
436
		for (Synonym synonym :synonyms ){
437
			SynonymType type = synonym.getType();
438
			if (type == null){ // should not happen
439
				type = SynonymType.SYNONYM_OF();
440
			}
441
			INonViralName name = synonym.getName();
442
			synonymLabels.add(name.getTitleCache());
443
		}
444
		record.setSynonyms(synonymLabels);
445
	}
446

    
447
	private void handleDiscriptionData(CsvDemoRecord record, Taxon taxon) {
448

    
449
		Set<TaxonDescription> descriptions = taxon.getDescriptions();
450
		ArrayList<String> distributions = new ArrayList<String>();
451
		for (TaxonDescription description : descriptions){
452
			for (DescriptionElementBase el : description.getElements()){
453
				if (el.isInstanceOf(Distribution.class) ){
454
						Distribution distribution = CdmBase.deproxy(el, Distribution.class);
455
						NamedArea area = distribution.getArea();
456
						distributions.add(area.getTitleCache());
457
				}
458

    
459
			}
460
		}
461
		record.setCountryCode(distributions);
462
	}
463

    
464
	private void handleRedlistStatus(CsvDemoRecord record, Taxon taxon, List<List<String>> featureCells, List<Feature> features){
465
		Set<TaxonDescription> descriptions = taxon.getDescriptions();
466

    
467
		for (TaxonDescription description : descriptions){
468
			for (DescriptionElementBase el : description.getElements()){
469
				if(el.isInstanceOf(CategoricalData.class)){
470
					CategoricalData categoricalData = CdmBase.deproxy(el, CategoricalData.class);
471
					for(State state:categoricalData.getStatesOnly()){
472
						Feature stateFeature = categoricalData.getFeature();
473
						// find matching feature and put data into according cell
474
						for(int i = 0; i < features.size(); i++) {
475
							if(features.get(i).equals(stateFeature)){
476
								List<String> cell = featureCells.get(i);
477
								cell.add(state.toString());
478
							}
479
						}
480
					}
481
				}else if(el.isInstanceOf(TextData.class)){
482
					TextData textData = CdmBase.deproxy(el, TextData.class);
483
					Feature textFeature = textData.getFeature();
484
					// find matching feature and put data into according cell
485
					for(int i = 0; i < features.size(); i++) {
486
						if(features.get(i).equals(textFeature)){
487
							List<String> cell = featureCells.get(i);
488
							String text = textData.getText(Language.GERMAN());
489
							text = text.replaceAll(System.getProperty("line.separator"), "");
490
							text = text.replaceAll("                            ", " ");
491
							cell.add(text);
492

    
493
						}
494
					}
495
				}
496
			}
497
		}
498
		record.setFeatures(featureCells);
499
	}
500

    
501
	private void handleRelatedRedlistStatus(CsvDemoRecord record, Taxon taxon, boolean relationFrom, List<List<String>> featureCells, List<Feature> features) {
502

    
503
		if (relationFrom) {
504
            handleRedlistStatus(record, taxon, featureCells, features);
505
        }
506

    
507
		Set<TaxonRelationship> taxRels;
508
		if(relationFrom){
509
			taxRels = taxon.getRelationsFromThisTaxon();
510
		}else{
511
			taxRels = taxon.getRelationsToThisTaxon();
512
		}
513
		for (TaxonRelationship taxRel:taxRels){
514
			if(taxRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO())){
515
				Taxon relatedTaxon;
516
				if(relationFrom){
517
					relatedTaxon = taxRel.getToTaxon();
518
				}else{
519
					relatedTaxon = taxRel.getFromTaxon();
520
				}
521
				handleRedlistStatus(record, relatedTaxon, featureCells, features);
522
			}
523
		}
524
	}
525

    
526
	private void sortTaxonNodes(List<TaxonNode> taxonNodes) {
527
		Collections.sort(taxonNodes, new Comparator<TaxonNode>() {
528

    
529
			@Override
530
			public int compare(TaxonNode tn1, TaxonNode tn2) {
531
				Taxon taxon1 = tn1.getTaxon();
532
				Taxon taxon2 = tn2.getTaxon();
533
				if(taxon1 != null && taxon2 != null){
534
					return taxon1.getTitleCache().compareTo(taxon2.getTitleCache());
535
				}
536
				else{
537
					return 0;
538
				}
539
			}
540
		});
541
	}
542

    
543
	@Override
544
	protected boolean doCheck(CsvDemoExportState state) {
545
		boolean result = true;
546
		logger.warn("No check implemented for " + this.ioName);
547
		return result;
548
	}
549

    
550
	@Override
551
	protected boolean isIgnore(CsvDemoExportState state) {
552
		return ! state.getConfig().isDoTaxa();
553
	}
554

    
555
    @Override
556
    public byte[] getByteArray() {
557
        if (this.exportStream != null){
558
            return this.exportStream.toByteArray();
559
        }
560
        return null;
561
    }
562
}
(2-2/10)