Project

General

Profile

Download (14 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, config);
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, config);
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, config);
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, DwcaTaxExportConfigurator config) {
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
		if (config.isWithHigherClassification()){
232
			//FIXME all classification and rank specific fields are meant to represent the classification
233
			//currently the information is only compiled for the exact same range but it should be compiled
234
			//for all ranks above the rank of this taxon
235
			//TODO we do not support this yet
236
			record.setHigherClassification(null);
237
			//... higher ranks
238
			handleUninomialOrGenus(record, name);
239
			if (name.getRank() != null &&  name.getRank().equals(Rank.SUBGENUS())){
240
				record.setSubgenus(name.getNameCache());	
241
			}
242
			//record.setSubgenus(name.getInfraGenericEpithet());
243
		}
244
		if (name.getRank() != null &&  (name.getRank().isSupraGeneric() || name.getRank().isGenus())){
245
			record.setUninomial(name.getGenusOrUninomial());
246
		}else{
247
			record.setGenusPart(name.getGenusOrUninomial());
248
		}
249
		record.setInfraGenericEpithet(name.getInfraGenericEpithet());
250
		
251
		record.setSpecificEpithet(name.getSpecificEpithet());
252
		record.setInfraspecificEpithet(name.getInfraSpecificEpithet());
253
		
254
		record.setTaxonRank(name.getRank());
255
		if (name.getRank() != null){
256
			record.setVerbatimTaxonRank(name.getRank().getAbbreviation());
257
		}else{
258
			String message = "No rank available for " + name.getTitleCache() + "(" + name.getId() + ")";
259
			logger.warn(message);
260
		}
261
		
262
		record.setScientificNameAuthorship(name.getAuthorshipCache());
263
		
264
		// ??? - use for TextData common names?
265
		record.setVernacularName(null);
266
		
267
		record.setNomenclaturalCode(name.getNomenclaturalCode());
268
		// ??? TODO Misapplied Names, inferred synonyms
269
		handleTaxonomicStatus(record, name, relType, isProParte, isPartial);
270
		handleNomStatus(record, taxonBase, name);
271
		
272
		// TODO we need to differentiate technical
273
		String taxonRemarks = "";
274
		for (Annotation annotation : taxonBase.getAnnotations()){
275
			if (AnnotationType.EDITORIAL().equals(annotation.getAnnotationType())){
276
				taxonRemarks += CdmUtils.Nz(annotation.getText());
277
			}
278
		}
279
		for (Annotation annotation : name.getAnnotations()){
280
			if (AnnotationType.EDITORIAL().equals(annotation.getAnnotationType())){
281
				taxonRemarks += CdmUtils.Nz(annotation.getText());
282
			}
283
		}
284
		if (StringUtils.isNotBlank(taxonRemarks)){
285
			record.setTaxonRemarks(taxonRemarks);
286
		}
287
		
288
		// TODO which date is needed here (taxon, name, sec, ... ?)
289
		record.setModified(taxonBase.getUpdated());
290
		
291
		// ???
292
		record.setLanguage(null);
293
		
294
		record.setRights(taxonBase.getRights());
295
		
296
		//TODO
297
		record.setRightsHolder(null);
298
		record.setAccessRights(null);
299
		
300
		//TODO currently only via default value
301
		record.setBibliographicCitation(null);
302
		record.setInformationWithheld(null);
303
		
304
		record.setDatasetId(classification);
305
		record.setDatasetName(classification.getTitleCache());
306
		
307
		//TODO
308
		record.setSource(null);
309
		
310
		return;
311
	}
312

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

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

    
380

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

    
401

    
402
	@Override
403
	protected boolean doCheck(DwcaTaxExportState state) {
404
		boolean result = true;
405
		logger.warn("No check implemented for " + this.ioName);
406
		return result;
407
	}
408

    
409

    
410
	@Override
411
	protected boolean isIgnore(DwcaTaxExportState state) {
412
		return ! state.getConfig().isDoTaxa();
413
	}
414
	
415
}
(18-18/30)