Project

General

Profile

Download (14.4 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

    
10
package eu.etaxonomy.cdm.io.csv.redlist.out;
11

    
12
import java.io.ByteArrayOutputStream;
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.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
23
import org.springframework.stereotype.Component;
24
import org.springframework.transaction.TransactionStatus;
25

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

    
47

    
48
/**
49
 * @author a.oppermann
50
 * @since 18.10.2012
51
 */
52

    
53
@Component
54
public class CsvTaxExportRedlist extends CsvExportBaseRedlist {
55
    private static final long serialVersionUID = 841703025922543361L;
56

    
57
    private static final Logger logger = LogManager.getLogger(CsvTaxExportRedlist.class);
58

    
59
	private static final String ROW_TYPE = "http://rs.tdwg.org/dwc/terms/Taxon";
60
	private static final String fileName = "RedlistCoreTax.csv";
61

    
62
	public CsvTaxExportRedlist() {
63
		super();
64
		this.ioName = this.getClass().getSimpleName();
65
	}
66

    
67

    
68
	/** Retrieves data from a CDM DB and serializes them CDM to CSV.
69
	 * Starts with root taxa and traverses the classification to retrieve
70
	 * children taxa, synonyms, relationships, descriptive data, red list
71
	 * status (features).
72
	 * Taxa that are not part of the classification are not found.
73
	 *
74
	 * @param exImpConfig
75
	 * @param dbname
76
	 * @param filename
77
	 */
78
	@Override
79
	protected void doInvoke(CsvTaxExportStateRedlist state){
80
		CsvTaxExportConfiguratorRedlist config = state.getConfig();
81
		TransactionStatus txStatus = startTransaction(true);
82
		List<NamedArea> selectedAreas = config.getNamedAreas();
83
		Set<TaxonNode> taxonNodes = assembleTaxonNodeSet(config);
84

    
85
		PrintWriter writer = null;
86
		ByteArrayOutputStream byteArrayOutputStream;
87
		try {
88
			byteArrayOutputStream = config.getByteArrayOutputStream();
89
			writer = new PrintWriter(byteArrayOutputStream);
90
			//geographical Filter
91
			List<TaxonNode> filteredNodes = handleGeographicalFilter(state, selectedAreas, taxonNodes);
92

    
93
			//sorting List
94
			Collections.sort(filteredNodes, new Comparator<TaxonNode>() {
95

    
96
				@Override
97
				public int compare(TaxonNode tn1, TaxonNode tn2) {
98
					Taxon taxon1 = tn1.getTaxon();
99
					Taxon taxon2 = tn2.getTaxon();
100
					if(taxon1 != null && taxon2 != null){
101
						return taxon1.getTitleCache().compareTo(taxon2.getTitleCache());
102
					}
103
					else{
104
						return 0;
105
					}
106
				}
107
			});
108
			for (TaxonNode node : filteredNodes){
109
				Taxon taxon = CdmBase.deproxy(node.getTaxon(), Taxon.class);
110
				CsvTaxRecordRedlist record = assembleRecord(state);
111
				INonViralName name = taxon.getName();
112
				Classification classification = node.getClassification();
113
				config.setClassificationTitleCache(classification.getTitleCache());
114
				if (! this.recordExists(taxon)){
115
					handleTaxonBase(record, taxon, name, taxon, classification, null, false, false, config);
116
					record.write(writer);
117
					this.addExistingRecord(taxon);
118
				}
119
				//misapplied names
120
				handleMisapplication(taxon, writer, classification, record, config);
121
				writer.flush();
122
			}
123
		} catch (ClassCastException e) {
124
			e.printStackTrace();
125
		}
126
		finally{
127
		    if(writer!=null){
128
		        writer.close();
129
		    }
130
			this.clearExistingRecordIds();
131
		}
132
		commitTransaction(txStatus);
133
		return;
134

    
135
	}
136

    
137

    
138
	//TODO: Exception handling
139
	protected Set<TaxonNode> assembleTaxonNodeSet(CsvTaxExportConfiguratorRedlist config){
140
		Set<TaxonNode> taxonNodes = new HashSet<>();
141
		if(config != null){
142
			List<UUID> taxonNodeUuidSet = new ArrayList<>(config.getTaxonNodeUuids());
143
			List<TaxonNode> loadedNodes = getTaxonNodeService().load(taxonNodeUuidSet, null);
144
			taxonNodes.addAll(loadedNodes);
145
		}
146
		return taxonNodes;
147
	}
148

    
149
	//TODO: Exception handling
150
	private CsvTaxRecordRedlist assembleRecord(CsvTaxExportStateRedlist state) {
151
		if(state!=null){
152
			CsvTaxExportConfiguratorRedlist config = state.getConfig();
153
			CsvMetaDataRecordRedlist metaRecord = new CsvMetaDataRecordRedlist(true, fileName, ROW_TYPE);
154
			state.addMetaRecord(metaRecord);
155
			CsvTaxRecordRedlist record = new CsvTaxRecordRedlist(metaRecord, config);
156
			return record;
157
		}
158
		return null;
159
	}
160

    
161
	/**
162
	 * Takes positive List of areas and iterates over a given taxon node
163
	 * and their {@link Taxon} to return all {@link Taxon} with the desired
164
	 * geographical attribute.
165
	 *
166
	 * <p><p>
167
	 *
168
	 * If selectedAreas is null all child {@link TaxonNode}s of the given taxon node will be returned.
169
	 * @param state
170
	 *
171
	 * @param selectedAreas
172
	 * @param taxonNodes
173
	 * @return
174
	 */
175
	protected List<TaxonNode> handleGeographicalFilter(CsvTaxExportStateRedlist state, List<NamedArea> selectedAreas,
176
	        Set<TaxonNode> taxonNodes) {
177
	    List<TaxonNode> filteredNodes = new ArrayList<>();
178
	    List<TaxonNode> allNodes = new ArrayList<>();
179
	    for (TaxonNode node : taxonNodes){
180
	        if(node.getTaxon()!=null){
181
	            allNodes.add(node);
182
	        }
183
	        allNodes.addAll(getTaxonNodeService().loadChildNodesOfTaxonNode(node, null, true,
184
	                state.getConfig().isIncludeUnpublished(), null));
185
	    }
186
	    //Geographical filter
187
	    if(selectedAreas != null && !selectedAreas.isEmpty() && selectedAreas.size() < 16){
188
	        for (TaxonNode node : allNodes){
189
	            Taxon taxon = CdmBase.deproxy(node.getTaxon(), Taxon.class);
190
	            Set<TaxonDescription> descriptions = taxon.getDescriptions();
191
	            for (TaxonDescription description : descriptions){
192
	                for (DescriptionElementBase el : description.getElements()){
193
	                    if (el.isInstanceOf(Distribution.class) ){
194
	                        Distribution distribution = CdmBase.deproxy(el, Distribution.class);
195
	                        NamedArea area = distribution.getArea();
196
	                        for(NamedArea selectedArea:selectedAreas){
197
	                            if(selectedArea.getUuid().equals(area.getUuid())){
198
	                                filteredNodes.add(node);
199
	                            }
200
	                        }
201
	                    }
202
	                }
203
	            }
204
	        }
205
	    }else{
206
	        filteredNodes = allNodes;
207
	    }
208
	    return filteredNodes;
209
	}
210

    
211
	/**
212
	 * handles misapplied {@link Taxon}
213
	 * @param taxon
214
	 * @param writer
215
	 * @param classification
216
	 * @param metaRecord
217
	 * @param config
218
	 */
219
	private void handleMisapplication(Taxon taxon, PrintWriter writer, Classification classification, CsvTaxRecordRedlist record, CsvTaxExportConfiguratorRedlist config) {
220
		Set<TaxonRelationship> misappliedNameRels = taxon.getMisappliedNameRelations();
221
		for (TaxonRelationship misappliedNameRel : misappliedNameRels ){
222
//			CsvTaxRecordRedlist record = new CsvTaxRecordRedlist(metaRecord, config);
223
			Taxon misappliedName = misappliedNameRel.getFromTaxon();
224
			INonViralName name = misappliedName.getName();
225

    
226
			if (! this.recordExists(misappliedName)){
227
				handleTaxonBase(record, misappliedName, name, taxon, classification,
228
				        misappliedNameRel.getType(), false, false, config);
229
				record.write(writer);
230
				this.addExistingRecord(misappliedName);
231
			}
232
		}
233
	}
234

    
235
	/**
236
	 * handles the information record for the actual {@link Taxon} including {@link Classification classification}, Taxon Name, Taxon ID,
237
	 * Taxon Status, Synonyms, {@link Feature features} data
238
	 * @param record the concrete information record
239
	 * @param taxonBase {@link Taxon}
240
	 * @param name
241
	 * @param acceptedTaxon
242
	 * @param parent
243
	 * @param basionym
244
	 * @param isPartial
245
	 * @param isProParte
246
	 * @param config
247
	 * @param type
248
	 */
249
	private void handleTaxonBase(CsvTaxRecordRedlist record,TaxonBase<?> taxonBase,
250
			INonViralName name, Taxon acceptedTaxon, Classification classification,
251
			RelationshipTermBase<?> relType, boolean isProParte, boolean isPartial,
252
			CsvTaxExportConfiguratorRedlist config) {
253

    
254
		List<Feature> features = config.getFeatures();
255
		record.setHeadLinePrinted(config.isHasHeaderLines());
256
		if(features != null) {
257
            record.setPrintFeatures(features);
258
        }
259
		config.setHasHeaderLines(false);
260

    
261
		record.setDatasetName(classification.getTitleCache());
262
		record.setScientificName(name.getTitleCache());
263
		record.setScientificNameId(name.getUuid().toString());
264
		handleTaxonomicStatus(record, name, relType, isProParte, isPartial);
265
		//synonyms
266
		handleSynonyms(record,(Taxon) taxonBase);
267
		//distribution
268
		handleDiscriptionData(record, (Taxon) taxonBase);
269
		if(features!= null) {
270

    
271
			List<List<String>> featureCells = new ArrayList<List<String>>(features.size());
272
			for(int i = 0; i < features.size(); i++) {
273
				featureCells.add(new ArrayList<String>());
274
			}
275
			handleRelatedRedlistStatus(record, (Taxon)taxonBase, false, featureCells, features);
276
			handleRelatedRedlistStatus(record, (Taxon)taxonBase, true, featureCells, features);
277

    
278
		}
279
		return;
280
	}
281

    
282
	private void handleTaxonomicStatus(
283
			CsvTaxRecordRedlist record,
284
			INonViralName name,
285
			RelationshipTermBase<?> type,
286
			boolean isProParte,
287
			boolean isPartial) {
288
		if (type == null){
289
			record.setTaxonomicStatus(name.getNameType().acceptedTaxonStatusLabel());
290
		}else{
291
			String status = name.getNameType().synonymStatusLabel();
292
			if (type.equals(SynonymType.HETEROTYPIC_SYNONYM_OF())){
293
				status = "heterotypicSynonym";
294
			}else if(type.equals(SynonymType.HOMOTYPIC_SYNONYM_OF())){
295
				status = "homotypicSynonym";
296
			}else if(type.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
297
				status = "misapplied";
298
			}else if(type.equals(TaxonRelationshipType.PRO_PARTE_MISAPPLIED_NAME_FOR())){
299
                status = "proParteMisapplied";
300
            }
301
			if (isProParte){
302
				status = "proParteSynonym";
303
			}else if (isPartial){
304
				String message = "Partial synonym is not part of the gbif toxonomic status vocabulary";
305
				logger.warn(message);
306
				status = "partialSynonym";
307
			}
308

    
309
			record.setTaxonomicStatus(status);
310
		}
311
	}
312

    
313
	private void handleSynonyms(CsvTaxRecordRedlist record, Taxon taxon) {
314

    
315
		Set<Synonym> synonyms = taxon.getSynonyms();
316
		ArrayList<String> synonymLabels = new ArrayList<>();
317
		for (Synonym synonym :synonyms ){
318
			SynonymType type = synonym.getType();
319
			if (type == null){ // should not happen
320
				type = SynonymType.SYNONYM_OF();
321
			}
322
			INonViralName name = synonym.getName();
323
			synonymLabels.add(name.getTitleCache());
324
		}
325
		record.setSynonyms(synonymLabels);
326
	}
327

    
328
	private void handleDiscriptionData(CsvTaxRecordRedlist record, Taxon taxon) {
329

    
330
		Set<TaxonDescription> descriptions = taxon.getDescriptions();
331
		ArrayList<String> distributions = new ArrayList<String>();
332
		for (TaxonDescription description : descriptions){
333
			for (DescriptionElementBase el : description.getElements()){
334
				if (el.isInstanceOf(Distribution.class) ){
335
						Distribution distribution = CdmBase.deproxy(el, Distribution.class);
336
						NamedArea area = distribution.getArea();
337
						distributions.add(area.getTitleCache());
338
				}
339

    
340
			}
341
		}
342
		record.setCountryCode(distributions);
343
	}
344

    
345
	private void handleRedlistStatus(CsvTaxRecordRedlist record, Taxon taxon, List<List<String>> featureCells, List<Feature> features){
346
		Set<TaxonDescription> descriptions = taxon.getDescriptions();
347

    
348
		for (TaxonDescription description : descriptions){
349
			for (DescriptionElementBase el : description.getElements()){
350
				if(el.isInstanceOf(CategoricalData.class)){
351
					CategoricalData categoricalData = CdmBase.deproxy(el, CategoricalData.class);
352
					for(State state:categoricalData.getStatesOnly()){
353
						Feature stateFeature = categoricalData.getFeature();
354
						// find matching feature and put data into according cell
355
						for(int i = 0; i < features.size(); i++) {
356
							if(features.get(i).equals(stateFeature)){
357
								List<String> cell = featureCells.get(i);
358
								cell.add(state.toString());
359
							}
360
						}
361
					}
362
				}else if(el.isInstanceOf(TextData.class)){
363
					TextData textData = CdmBase.deproxy(el, TextData.class);
364
					Feature textFeature = textData.getFeature();
365
					// find matching feature and put data into according cell
366
					for(int i = 0; i < features.size(); i++) {
367
						if(features.get(i).equals(textFeature)){
368
							List<String> cell = featureCells.get(i);
369
							String text = textData.getText(Language.GERMAN());
370
							text = text.replaceAll(System.getProperty("line.separator"), "");
371
							text = text.replaceAll("                            ", " ");
372
							cell.add(text);
373

    
374
						}
375
					}
376
				}
377
			}
378
		}
379
		record.setFeatures(featureCells);
380
	}
381

    
382

    
383
	private void handleRelatedRedlistStatus(CsvTaxRecordRedlist record, Taxon taxon, boolean relationFrom, List<List<String>> featureCells, List<Feature> features) {
384

    
385
		if (relationFrom) {
386
            handleRedlistStatus(record, taxon, featureCells, features);
387
        }
388

    
389

    
390
		Set<TaxonRelationship> taxRels;
391
		if(relationFrom){
392
			taxRels = taxon.getRelationsFromThisTaxon();
393
		}else{
394
			taxRels = taxon.getRelationsToThisTaxon();
395
		}
396
		for (TaxonRelationship taxRel:taxRels){
397
			if(taxRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO())){
398
				Taxon relatedTaxon;
399
				if(relationFrom){
400
					relatedTaxon = taxRel.getToTaxon();
401
				}else{
402
					relatedTaxon = taxRel.getFromTaxon();
403
				}
404
				handleRedlistStatus(record, relatedTaxon, featureCells, features);
405
			}
406
		}
407
	}
408

    
409
	@Override
410
	protected boolean doCheck(CsvTaxExportStateRedlist state) {
411
		boolean result = true;
412
		logger.warn("No check implemented for " + this.ioName);
413
		return result;
414
	}
415

    
416
	@Override
417
	protected boolean isIgnore(CsvTaxExportStateRedlist state) {
418
		return ! state.getConfig().isDoTaxa();
419
	}
420

    
421

    
422

    
423

    
424
}
(6-6/10)