Project

General

Profile

Download (13.6 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.dwca.out;
11

    
12
import java.io.FileNotFoundException;
13
import java.io.IOException;
14
import java.io.PrintWriter;
15
import java.io.UnsupportedEncodingException;
16
import java.util.List;
17
import java.util.Set;
18

    
19
import org.apache.commons.lang.StringUtils;
20
import org.apache.log4j.Logger;
21
import org.springframework.stereotype.Component;
22
import org.springframework.transaction.TransactionStatus;
23

    
24
import eu.etaxonomy.cdm.common.CdmUtils;
25
import eu.etaxonomy.cdm.model.common.Annotation;
26
import eu.etaxonomy.cdm.model.common.AnnotationType;
27
import eu.etaxonomy.cdm.model.common.CdmBase;
28
import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
29
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
30
import eu.etaxonomy.cdm.model.name.NonViralName;
31
import eu.etaxonomy.cdm.model.name.Rank;
32
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
33
import eu.etaxonomy.cdm.model.reference.Reference;
34
import eu.etaxonomy.cdm.model.taxon.Classification;
35
import eu.etaxonomy.cdm.model.taxon.Synonym;
36
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
37
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
38
import eu.etaxonomy.cdm.model.taxon.Taxon;
39
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
40
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
41
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
42

    
43
/**
44
 * @author a.mueller
45
 * @created 18.04.2011
46
 */
47
@Component
48
public class DwcaTaxExport extends DwcaExportBase {
49
	private static final Logger logger = Logger.getLogger(DwcaTaxExport.class);
50

    
51
	private static final String ROW_TYPE = "http://rs.tdwg.org/dwc/terms/Taxon";
52
	private static final String fileName = "coreTax.txt";
53
	
54
	/**
55
	 * 
56
	 */
57
	public DwcaTaxExport() {
58
		super();
59
		this.ioName = this.getClass().getSimpleName();
60
	}
61

    
62
	/** Retrieves data from a CDM DB and serializes them CDM to XML.
63
	 * Starts with root taxa and traverses the classification to retrieve children taxa, synonyms and relationships.
64
	 * Taxa that are not part of the classification are not found.
65
	 * 
66
	 * @param exImpConfig
67
	 * @param dbname
68
	 * @param filename
69
	 */
70
	@Override
71
	protected boolean doInvoke(DwcaTaxExportState state){
72
		DwcaTaxExportConfigurator config = state.getConfig();
73
		TransactionStatus txStatus = startTransaction(true);
74
		
75
		DwcaMetaDataRecord metaRecord = new DwcaMetaDataRecord(true, fileName, ROW_TYPE);
76
		state.addMetaRecord(metaRecord);
77
		
78
		PrintWriter writer = null;
79
		try {
80
			
81
			writer = createPrintWriter(fileName, state);
82

    
83
			List<TaxonNode> allNodes =  getAllNodes(null);
84
			int i = 0;
85
			for (TaxonNode node : allNodes){
86
				i++;
87
				Taxon taxon = CdmBase.deproxy(node.getTaxon(), Taxon.class);
88
				DwcaTaxRecord record = new DwcaTaxRecord(metaRecord, config);
89
				
90
				NonViralName<?> name = CdmBase.deproxy(taxon.getName(), NonViralName.class);
91
				Taxon parent = node.getParent() == null ? null : node.getParent().getTaxon();
92
				TaxonNameBase<?, ?> basionym = name.getBasionym();
93
				Classification classification = node.getClassification();
94
				if (! this.recordExists(taxon)){
95
					handleTaxonBase(record, taxon, name, taxon, parent, basionym, classification, null, false, false);
96
					record.write(writer);
97
					this.addExistingRecord(taxon);
98
				}
99
				
100
				node.getClassification().getName();
101
				//synonyms
102
				handleSynonyms(taxon, writer, classification, metaRecord, config);
103
				
104
				//misapplied names
105
				handleMisapplication(taxon, writer, classification, metaRecord, config);
106
				
107
				writer.flush();
108
				
109
			}
110
		} catch (FileNotFoundException e) {
111
			e.printStackTrace();
112
		} catch (UnsupportedEncodingException e) {
113
			e.printStackTrace();
114
		} catch (ClassCastException e) {
115
			e.printStackTrace();
116
		} catch (IOException e) {
117
			e.printStackTrace();
118
		}
119
		finally{
120
			closeWriter(writer, state);
121
		}
122
		commitTransaction(txStatus);
123
		return true;
124
		
125
	}
126

    
127
	private void handleSynonyms(Taxon taxon, PrintWriter writer, Classification classification, DwcaMetaDataRecord metaRecord, DwcaTaxExportConfigurator config) {
128
		Set<SynonymRelationship> synRels = taxon.getSynonymRelations();
129
		for (SynonymRelationship synRel :synRels ){
130
			DwcaTaxRecord record = new DwcaTaxRecord(metaRecord, config);
131
			Synonym synonym = synRel.getSynonym();
132
			SynonymRelationshipType type = synRel.getType();
133
			boolean isProParte = synRel.isProParte();
134
			boolean isPartial = synRel.isPartial();
135
			if (type == null){ // should not happen
136
				type = SynonymRelationshipType.SYNONYM_OF();
137
			}
138
			NonViralName<?> name = CdmBase.deproxy(synonym.getName(), NonViralName.class);
139
			//????
140
			Taxon parent = null;
141
			TaxonNameBase<?, ?> basionym = name.getBasionym();
142
			
143
			if (! this.recordExists(synonym)){
144
				handleTaxonBase(record, synonym, name, taxon, parent, basionym, classification, type, isProParte, isPartial);
145
				record.write(writer);
146
				this.addExistingRecord(synonym);
147
			}
148
			
149
		}
150
		
151
	}
152
	
153

    
154
	private void handleMisapplication(Taxon taxon, PrintWriter writer, Classification classification, DwcaMetaDataRecord metaRecord, DwcaTaxExportConfigurator config) {
155
		Set<Taxon> misappliedNames = taxon.getMisappliedNames();
156
		for (Taxon misappliedName : misappliedNames ){
157
			DwcaTaxRecord record = new DwcaTaxRecord(metaRecord, config);
158
			TaxonRelationshipType relType = TaxonRelationshipType.MISAPPLIED_NAME_FOR();
159
			NonViralName<?> name = CdmBase.deproxy(misappliedName.getName(), NonViralName.class);
160
			//????
161
			Taxon parent = null;
162
			TaxonNameBase<?, ?> basionym = name.getBasionym();
163
			
164
			if (! this.recordExists(misappliedName)){
165
				handleTaxonBase(record, misappliedName, name, taxon, parent, basionym, classification, relType, false, false);
166
				record.write(writer);
167
				this.addExistingRecord(misappliedName);
168
			}
169
		}	
170
	}
171

    
172
	/**
173
	 * @param record
174
	 * @param taxonBase
175
	 * @param name
176
	 * @param acceptedTaxon
177
	 * @param parent
178
	 * @param basionym
179
	 * @param isPartial 
180
	 * @param isProParte 
181
	 * @param config 
182
	 * @param type
183
	 */
184
	private void handleTaxonBase(DwcaTaxRecord record, TaxonBase<?> taxonBase, NonViralName<?> name, 
185
			Taxon acceptedTaxon, Taxon parent, TaxonNameBase<?, ?> basionym, Classification classification, 
186
			RelationshipTermBase<?> relType, boolean isProParte, boolean isPartial) {
187
		record.setId(taxonBase.getId());
188
		record.setUuid(taxonBase.getUuid());
189
		
190
		//maybe wrong as according to the DwC-A documentation only resolvable ids are allowed, this differs from DwC documentation
191
		record.setScientificNameId(name);
192
		record.setScientificName(name.getTitleCache());
193
		
194
		record.setAcceptedNameUsageId(acceptedTaxon.getUuid());
195
		record.setAcceptedNameUsage(acceptedTaxon.getName() == null? acceptedTaxon.getTitleCache() : acceptedTaxon.getName().getTitleCache());
196
		
197
		//parentNameUsage
198
		if (parent != null){
199
			record.setParentNameUsageId(parent.getUuid());
200
			record.setParentNameUsage(parent.getTitleCache());
201
		}
202
		
203
		//originalNameUsage
204
		// ??? - is not a name usage (concept)
205
		if (basionym != null){
206
			record.setOriginalNameUsageId(basionym.getUuid());
207
			record.setOriginalNameUsage(basionym.getTitleCache());
208
		}
209
		
210
		//nameAccordingTo
211
		Reference<?> sec = taxonBase.getSec();
212
		if (sec == null){
213
			String message = "There is a taxon without sec " + taxonBase.getTitleCache() + "( " + taxonBase.getId() + ")";
214
			logger.warn(message);
215
		}else{
216
			record.setNameAccordingToId(taxonBase.getSec().getUuid());
217
			record.setNameAccordingTo(taxonBase.getSec().getTitleCache());
218
		}
219
		
220
		//namePublishedIn
221
		// ??? is not a nameUsage (concept)
222
		if (name.getNomenclaturalReference() != null){
223
			record.setNamePublishedInId(name.getNomenclaturalReference().getUuid());
224
			record.setNamePublishedIn(name.getNomenclaturalReference() == null ? null : name.getNomenclaturalReference().getTitleCache());
225
		}
226
			
227
		// what is the exact difference to id and acceptedNameUsageId
228
		record.setTaxonConceptId(taxonBase.getUuid());
229
		
230
		//Classification
231
		//FIXME all classification and rank specific fields are meant to represent the classification
232
		//currently the information is only compiled for the exact same range but it should be compiled
233
		//for all ranks above the rank of this taxon
234
		//TODO we do not support this yet
235
		record.setHigherClassification(null);
236
		//... higher ranks
237
		handleUninomialOrGenus(record, name);
238
		if (name.getRank() != null &&  name.getRank().equals(Rank.SUBGENUS())){
239
			record.setSubgenus(name.getNameCache());	
240
		}
241
		//record.setSubgenus(name.getInfraGenericEpithet());
242
		
243
		
244
		record.setSpecificEpithet(name.getSpecificEpithet());
245
		record.setInfraspecificEpithet(name.getInfraSpecificEpithet());
246
		
247
		record.setTaxonRank(name.getRank());
248
		if (name.getRank() != null){
249
			record.setVerbatimTaxonRank(name.getRank().getAbbreviation());
250
		}else{
251
			String message = "No rank available for " + name.getTitleCache() + "(" + name.getId() + ")";
252
			logger.warn(message);
253
		}
254
		
255
		record.setScientificNameAuthorship(name.getAuthorshipCache());
256
		
257
		// ??? - use for TextData common names?
258
		record.setVernacularName(null);
259
		
260
		record.setNomenclaturalCode(name.getNomenclaturalCode());
261
		// ??? TODO Misapplied Names, inferred synonyms
262
		handleTaxonomicStatus(record, name, relType, isProParte, isPartial);
263
		handleNomStatus(record, taxonBase, name);
264
		
265
		// TODO we need to differentiate technical
266
		String taxonRemarks = "";
267
		for (Annotation annotation : taxonBase.getAnnotations()){
268
			if (AnnotationType.EDITORIAL().equals(annotation.getAnnotationType())){
269
				taxonRemarks += CdmUtils.Nz(annotation.getText());
270
			}
271
		}
272
		for (Annotation annotation : name.getAnnotations()){
273
			if (AnnotationType.EDITORIAL().equals(annotation.getAnnotationType())){
274
				taxonRemarks += CdmUtils.Nz(annotation.getText());
275
			}
276
		}
277
		if (StringUtils.isNotBlank(taxonRemarks)){
278
			record.setTaxonRemarks(taxonRemarks);
279
		}
280
		
281
		// TODO which date is needed here (taxon, name, sec, ... ?)
282
		record.setModified(taxonBase.getUpdated());
283
		
284
		// ???
285
		record.setLanguage(null);
286
		
287
		record.setRights(taxonBase.getRights());
288
		
289
		//TODO
290
		record.setRightsHolder(null);
291
		record.setAccessRights(null);
292
		
293
		//TODO currently only via default value
294
		record.setBibliographicCitation(null);
295
		record.setInformationWithheld(null);
296
		
297
		record.setDatasetId(classification);
298
		record.setDatasetName(classification.getTitleCache());
299
		
300
		//TODO
301
		record.setSource(null);
302
		
303
		return;
304
	}
305

    
306
	/**
307
	 * @param record
308
	 * @param name
309
	 * @param type
310
	 * @param isPartial 
311
	 * @param isProParte 
312
	 */
313
	private void handleTaxonomicStatus(DwcaTaxRecord record,
314
			NonViralName<?> name, RelationshipTermBase<?> type, boolean isProParte, boolean isPartial) {
315
		if (type == null){
316
			record.setTaxonomicStatus(name.getNomenclaturalCode().acceptedTaxonStatusLabel());
317
		}else{
318
			String status = name.getNomenclaturalCode().synonymStatusLabel();
319
			if (type.equals(SynonymRelationshipType.HETEROTYPIC_SYNONYM_OF())){
320
				status = "heterotypicSynonym";
321
			}else if(type.equals(SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF())){
322
				status = "homotypicSynonym";
323
			}else if(type.equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR())){
324
				status = "misapplied";
325
			}
326
			if (isProParte){
327
				status = "proParteSynonym";
328
			}else if (isPartial){
329
				String message = "Partial synonym is not part of the gbif toxonomic status vocabulary";
330
				logger.warn(message);
331
				status = "partialSynonym";
332
			}
333
			
334
			record.setTaxonomicStatus(status);
335
		}
336
	}
337

    
338
	/**
339
	 * @param record
340
	 * @param name
341
	 */
342
	private void handleUninomialOrGenus(DwcaTaxRecord record, NonViralName<?> name) {
343
		//epethita
344
		String firstEpi = name.getGenusOrUninomial();
345
		if (!StringUtils.isBlank(firstEpi)){
346
			Rank rank = name.getRank();
347
			if (rank != null){
348
				if (rank.isLower(Rank.GENUS())){
349
					record.setGenus(firstEpi);	
350
				}else if (rank.equals(Rank.GENUS())){
351
					record.setGenus(firstEpi);	
352
				}else if (rank.equals(Rank.KINGDOM())){
353
					record.setKingdom(firstEpi);	
354
				}else if (rank.equals(Rank.PHYLUM())){
355
					record.setPhylum(firstEpi);	
356
				}else if (rank.equals(Rank.CLASS())){
357
					record.setClazz(firstEpi);	
358
				}else if (rank.equals(Rank.ORDER())){
359
					record.setOrder(firstEpi);	
360
				}else if (rank.equals(Rank.FAMILY())){
361
					record.setFamily(firstEpi);	
362
				}else{
363
					// !!!
364
					String message = "Rank not covered. Set uninomial as genus instead: " + rank.getLabel();
365
					logger.warn(message);
366
//					record.setGenus(firstEpi);	
367
				} 
368
				
369
			}
370
		}
371
	}
372

    
373

    
374
	/**
375
	 * @param record
376
	 * @param taxon
377
	 * @param name
378
	 */
379
	private void handleNomStatus(DwcaTaxRecord record, TaxonBase<?> taxon,
380
			NonViralName<?> name) {
381
		int nStatus = name.getStatus().size();
382
		if (nStatus > 0){
383
			if (name.getStatus().size()> 1){
384
				String warning = "There is more than 1 nomenclatural status ( " + name.getStatus().size()+ "): " + taxon.getTitleCache();
385
				logger.warn(warning);
386
			}
387
			NomenclaturalStatusType status = name.getStatus().iterator().next().getType();
388
			record.setNomenclaturalStatus(status);
389
		}else{
390
			record.setNomenclaturalStatus(null);
391
		}
392
	}
393

    
394

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

    
402

    
403
	@Override
404
	protected boolean isIgnore(DwcaTaxExportState state) {
405
		return ! state.getConfig().isDoTaxa();
406
	}
407
	
408
}
(18-18/30)