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 void 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;
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
			//FIXME needs to be a coreID otherwise use string only
207
//			record.setOriginalNameUsageId(basionym.getUuid());
208
			record.setOriginalNameUsageId(null);
209
			record.setOriginalNameUsage(basionym.getTitleCache());
210
		}
211
		
212
		//nameAccordingTo
213
		Reference<?> sec = taxonBase.getSec();
214
		if (sec == null){
215
			String message = "There is a taxon without sec " + taxonBase.getTitleCache() + "( " + taxonBase.getId() + ")";
216
			logger.warn(message);
217
		}else{
218
			record.setNameAccordingToId(taxonBase.getSec().getUuid());
219
			record.setNameAccordingTo(taxonBase.getSec().getTitleCache());
220
		}
221
		
222
		//namePublishedIn
223
		// ??? is not a nameUsage (concept)
224
		if (name.getNomenclaturalReference() != null){
225
			record.setNamePublishedInId(name.getNomenclaturalReference().getUuid());
226
			record.setNamePublishedIn(name.getNomenclaturalReference() == null ? null : name.getNomenclaturalReference().getTitleCache());
227
		}
228
			
229
		// what is the exact difference to id and acceptedNameUsageId
230
		record.setTaxonConceptId(taxonBase.getUuid());
231
		
232
		//Classification
233
		if (config.isWithHigherClassification()){
234
			//FIXME all classification and rank specific fields are meant to represent the classification
235
			//currently the information is only compiled for the exact same range but it should be compiled
236
			//for all ranks above the rank of this taxon
237
			//TODO we do not support this yet
238
			record.setHigherClassification(null);
239
			//... higher ranks
240
			handleUninomialOrGenus(record, name);
241
			if (name.getRank() != null &&  name.getRank().equals(Rank.SUBGENUS())){
242
				record.setSubgenus(name.getNameCache());	
243
			}
244
			//record.setSubgenus(name.getInfraGenericEpithet());
245
		}
246
		if (name.getRank() != null &&  (name.getRank().isSupraGeneric() || name.getRank().isGenus())){
247
			record.setUninomial(name.getGenusOrUninomial());
248
		}else{
249
			record.setGenusPart(name.getGenusOrUninomial());
250
		}
251
		record.setInfraGenericEpithet(name.getInfraGenericEpithet());
252
		
253
		record.setSpecificEpithet(name.getSpecificEpithet());
254
		record.setInfraspecificEpithet(name.getInfraSpecificEpithet());
255
		
256
		record.setTaxonRank(name.getRank());
257
		if (name.getRank() != null){
258
			record.setVerbatimTaxonRank(name.getRank().getAbbreviation());
259
		}else{
260
			String message = "No rank available for " + name.getTitleCache() + "(" + name.getId() + ")";
261
			logger.warn(message);
262
		}
263
		
264
		record.setScientificNameAuthorship(name.getAuthorshipCache());
265
		
266
		// ??? - use for TextData common names?
267
		record.setVernacularName(null);
268
		
269
		record.setNomenclaturalCode(name.getNomenclaturalCode());
270
		// ??? TODO Misapplied Names, inferred synonyms
271
		handleTaxonomicStatus(record, name, relType, isProParte, isPartial);
272
		handleNomStatus(record, taxonBase, name);
273
		
274
		// TODO we need to differentiate technical
275
		String taxonRemarks = "";
276
		for (Annotation annotation : taxonBase.getAnnotations()){
277
			if (AnnotationType.EDITORIAL().equals(annotation.getAnnotationType())){
278
				taxonRemarks += CdmUtils.Nz(annotation.getText());
279
			}
280
		}
281
		for (Annotation annotation : name.getAnnotations()){
282
			if (AnnotationType.EDITORIAL().equals(annotation.getAnnotationType())){
283
				taxonRemarks += CdmUtils.Nz(annotation.getText());
284
			}
285
		}
286
		if (StringUtils.isNotBlank(taxonRemarks)){
287
			record.setTaxonRemarks(taxonRemarks);
288
		}
289
		
290
		// TODO which date is needed here (taxon, name, sec, ... ?)
291
		record.setModified(taxonBase.getUpdated());
292
		
293
		// ???
294
		record.setLanguage(null);
295
		
296
		record.setRights(taxonBase.getRights());
297
		
298
		//TODO
299
		record.setRightsHolder(null);
300
		record.setAccessRights(null);
301
		
302
		//TODO currently only via default value
303
		record.setBibliographicCitation(null);
304
		record.setInformationWithheld(null);
305
		
306
		record.setDatasetId(classification);
307
		record.setDatasetName(classification.getTitleCache());
308
		
309
		//TODO
310
		record.setSource(null);
311
		
312
		return;
313
	}
314

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

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

    
382

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

    
403

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

    
411

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