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.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.NonViralName;
38
import eu.etaxonomy.cdm.model.taxon.Classification;
39
import eu.etaxonomy.cdm.model.taxon.Synonym;
40
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
41
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
42
import eu.etaxonomy.cdm.model.taxon.Taxon;
43
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
44
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
45
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
46
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
47

    
48

    
49
/**
50
 * @author a.oppermann
51
 * @created 18.10.2012
52
 */
53

    
54
@Component
55
public class CsvTaxExportRedlist extends CsvExportBaseRedlist {
56
	private static final Logger logger = Logger.getLogger(CsvTaxExportRedlist.class);
57

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

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

    
67
	/** Retrieves data from a CDM DB and serializes them CDM to CSV.
68
	 * Starts with root taxa and traverses the classification to retrieve 
69
	 * children taxa, synonyms, relationships, descriptive data, red list 
70
	 * status (features). 
71
	 * Taxa that are not part of the classification are not found.
72
	 * 
73
	 * @param exImpConfig
74
	 * @param dbname
75
	 * @param filename
76
	 */
77
	@Override
78
	protected void doInvoke(CsvTaxExportStateRedlist state){
79
		CsvTaxExportConfiguratorRedlist config = state.getConfig();
80
		TransactionStatus txStatus = startTransaction(true);
81
		List<NamedArea> selectedAreas = config.getNamedAreas();
82
		Set<TaxonNode> taxonNodes = assembleTaxonNodeSet(config);
83
		
84
		PrintWriter writer = null;
85
		ByteArrayOutputStream byteArrayOutputStream;
86
		try {
87
			byteArrayOutputStream = config.getByteArrayOutputStream();
88
			writer = new PrintWriter(byteArrayOutputStream); 
89
			//geographical Filter
90
			List<TaxonNode> filteredNodes = handleGeographicalFilter(selectedAreas, taxonNodes);
91
			
92
			//sorting List
93
			Collections.sort(filteredNodes, new Comparator<TaxonNode>() {
94

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

    
132
	}
133
	
134
	
135
	//TODO: Exception handling
136
	protected Set<TaxonNode> assembleTaxonNodeSet(CsvTaxExportConfiguratorRedlist config){
137
		Set<TaxonNode> taxonNodes = new HashSet<>();
138
		if(config != null){
139
			Set<UUID> taxonNodeUuidSet = config.getTaxonNodeUuids();
140
			taxonNodes.addAll(getTaxonNodeService().find(taxonNodeUuidSet));
141
		}
142
		return taxonNodes;
143
	}
144

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

    
157
	/**
158
	 * Takes positive List of areas and iterates over a given taxon node 
159
	 * and their {@link Taxon} to return all {@link Taxon} with the desired 
160
	 * geographical attribute.
161
	 * 
162
	 * <p><p>
163
	 *
164
	 * If selectedAreas is null all child {@link TaxonNode}s of the given taxon node will be returned.
165
	 * 
166
	 * @param selectedAreas 
167
	 * @param taxonNodes
168
	 * @return
169
	 */
170
	protected List<TaxonNode> handleGeographicalFilter(List<NamedArea> selectedAreas,
171
			Set<TaxonNode> taxonNodes) {
172
		List<TaxonNode> filteredNodes = new ArrayList<TaxonNode>();
173
		List<TaxonNode> allNodes =  new ArrayList(getAllNodes(taxonNodes));
174
		//Geographical filter
175
		logger.info(selectedAreas.size());
176
		if(selectedAreas != null && !selectedAreas.isEmpty() && selectedAreas.size() < 16){
177
//				if(selectedAreas.size() == 16){
178
//					//Germany TDWG Level 3
179
//					String germany="uu7b7c2db5-aa44-4302-bdec-6556fd74b0b9id";
180
//					selectedAreas.add((NamedArea) getTermService().find(UUID.fromString(germany)));
181
//				}
182
			for (TaxonNode node : allNodes){
183
				Taxon taxon = CdmBase.deproxy(node.getTaxon(), Taxon.class);
184
				Set<TaxonDescription> descriptions = taxon.getDescriptions();
185
				for (TaxonDescription description : descriptions){
186
					for (DescriptionElementBase el : description.getElements()){
187
						if (el.isInstanceOf(Distribution.class) ){
188
							Distribution distribution = CdmBase.deproxy(el, Distribution.class);
189
							NamedArea area = distribution.getArea();
190
							for(NamedArea selectedArea:selectedAreas){
191
								if(selectedArea.getUuid().equals(area.getUuid())){
192
									filteredNodes.add(node);
193
								}
194
							}
195
						}
196
					}
197
				}
198
			}
199
		}else{
200
			filteredNodes = allNodes;
201
		}
202
		return filteredNodes;
203
	}
204

    
205
	/**
206
	 * handles misapplied {@link Taxon}
207
	 * @param taxon
208
	 * @param writer
209
	 * @param classification
210
	 * @param metaRecord
211
	 * @param config
212
	 */
213
	private void handleMisapplication(Taxon taxon, PrintWriter writer, Classification classification, CsvTaxRecordRedlist record, CsvTaxExportConfiguratorRedlist config) {
214
		Set<Taxon> misappliedNames = taxon.getMisappliedNames();
215
		for (Taxon misappliedName : misappliedNames ){
216
//			CsvTaxRecordRedlist record = new CsvTaxRecordRedlist(metaRecord, config);
217
			TaxonRelationshipType relType = TaxonRelationshipType.MISAPPLIED_NAME_FOR();
218
			NonViralName<?> name = CdmBase.deproxy(misappliedName.getName(), NonViralName.class);
219
		
220
			if (! this.recordExists(misappliedName)){
221
				handleTaxonBase(record, misappliedName, name, taxon, classification, relType, false, false, config);
222
				record.write(writer);
223
				this.addExistingRecord(misappliedName);
224
			}
225
		}	
226
	}
227

    
228
	/**
229
	 * handles the information record for the actual {@link Taxon} including {@link Classification classification}, Taxon Name, Taxon ID,
230
	 * Taxon Status, Synonyms, {@link Feature features} data 
231
	 * @param record the concrete information record
232
	 * @param taxonBase {@link Taxon}
233
	 * @param name
234
	 * @param acceptedTaxon
235
	 * @param parent
236
	 * @param basionym
237
	 * @param isPartial 
238
	 * @param isProParte 
239
	 * @param config 
240
	 * @param type
241
	 */
242
	private void handleTaxonBase(CsvTaxRecordRedlist record,TaxonBase<?> taxonBase,
243
			NonViralName<?> name, Taxon acceptedTaxon, Classification classification, 
244
			RelationshipTermBase<?> relType, boolean isProParte, boolean isPartial, 
245
			CsvTaxExportConfiguratorRedlist config) {
246
		
247
		List<Feature> features = config.getFeatures();
248
		record.setHeadLinePrinted(config.isHasHeaderLines());
249
		if(features != null)record.setPrintFeatures(features);
250
		config.setHasHeaderLines(false);
251

    
252
		record.setDatasetName(classification.getTitleCache());
253
		record.setScientificName(name.getTitleCache());
254
		record.setScientificNameId(name.getUuid().toString());
255
		handleTaxonomicStatus(record, name, relType, isProParte, isPartial);
256
		//synonyms
257
		handleSynonyms(record,(Taxon) taxonBase);
258
		//distribution
259
		handleDiscriptionData(record, (Taxon) taxonBase);
260
		if(features!= null) {
261
			
262
			List<List<String>> featureCells = new ArrayList<List<String>>(features.size());
263
			for(int i = 0; i < features.size(); i++) {
264
				featureCells.add(new ArrayList<String>());
265
			}
266
			handleRelatedRedlistStatus(record, (Taxon)taxonBase, false, featureCells, features);
267
			handleRelatedRedlistStatus(record, (Taxon)taxonBase, true, featureCells, features);
268

    
269
		}
270
		return;
271
	}
272

    
273
	private void handleTaxonomicStatus(
274
			CsvTaxRecordRedlist record,
275
			NonViralName<?> name, 
276
			RelationshipTermBase<?> type,
277
			boolean isProParte,
278
			boolean isPartial) {
279
		if (type == null){
280
			record.setTaxonomicStatus(name.getNomenclaturalCode().acceptedTaxonStatusLabel());
281
		}else{
282
			String status = name.getNomenclaturalCode().synonymStatusLabel();
283
			if (type.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
284
				status = "heterotypicSynonym";
285
			}else if(type.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
286
				status = "homotypicSynonym";
287
			}else if(type.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
288
				status = "misapplied";
289
			}
290
			if (isProParte){
291
				status = "proParteSynonym";
292
			}else if (isPartial){
293
				String message = "Partial synonym is not part of the gbif toxonomic status vocabulary";
294
				logger.warn(message);
295
				status = "partialSynonym";
296
			}
297
			
298
			record.setTaxonomicStatus(status);
299
		}
300
	}
301

    
302
	private void handleSynonyms(CsvTaxRecordRedlist record, Taxon taxon) {
303
		
304
		Set<SynonymRelationship> synRels = taxon.getSynonymRelations();
305
		ArrayList<String> synonyms = new ArrayList<String>(); 
306
		for (SynonymRelationship synRel :synRels ){
307
			Synonym synonym = synRel.getSynonym();
308
			SynonymRelationshipType type = synRel.getType();
309
			if (type == null){ // should not happen
310
				type = SynonymRelationshipType.SYNONYM_OF();
311
			}
312
			NonViralName<?> name = CdmBase.deproxy(synonym.getName(), NonViralName.class);
313
			synonyms.add(name.getTitleCache());
314
		}
315
		record.setSynonyms(synonyms);
316
	}
317

    
318
	private void handleDiscriptionData(CsvTaxRecordRedlist record, Taxon taxon) {
319
		
320
		Set<TaxonDescription> descriptions = taxon.getDescriptions();
321
		ArrayList<String> distributions = new ArrayList<String>();
322
		for (TaxonDescription description : descriptions){
323
			for (DescriptionElementBase el : description.getElements()){
324
				if (el.isInstanceOf(Distribution.class) ){
325
						Distribution distribution = CdmBase.deproxy(el, Distribution.class);
326
						NamedArea area = distribution.getArea();
327
						distributions.add(area.getTitleCache());
328
				}
329

    
330
			}
331
		}
332
		record.setCountryCode(distributions);
333
	}
334

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

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

    
372

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

    
375
		if (relationFrom)handleRedlistStatus(record, taxon, featureCells, features);
376
		
377
		
378
		Set<TaxonRelationship> taxRels;
379
		if(relationFrom){
380
			taxRels = taxon.getRelationsFromThisTaxon();
381
		}else{
382
			taxRels = taxon.getRelationsToThisTaxon();
383
		}
384
		for (TaxonRelationship taxRel:taxRels){
385
			if(taxRel.getType().equals(TaxonRelationshipType.CONGRUENT_TO())){
386
				Taxon relatedTaxon;
387
				if(relationFrom){
388
					relatedTaxon = taxRel.getToTaxon();
389
				}else{
390
					relatedTaxon = taxRel.getFromTaxon();
391
				}
392
				handleRedlistStatus(record, relatedTaxon, featureCells, features);
393
			}
394
		}
395
	}
396

    
397
	@Override
398
	protected boolean doCheck(CsvTaxExportStateRedlist state) {
399
		boolean result = true;
400
		logger.warn("No check implemented for " + this.ioName);
401
		return result;
402
	}
403

    
404
	@Override
405
	protected boolean isIgnore(CsvTaxExportStateRedlist state) {
406
		return ! state.getConfig().isDoTaxa();
407
	}
408
	
409
}
(6-6/10)