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.excel.taxa;
|
11
|
|
12
|
import java.net.MalformedURLException;
|
13
|
import java.net.URI;
|
14
|
import java.net.URISyntaxException;
|
15
|
import java.util.Arrays;
|
16
|
import java.util.HashMap;
|
17
|
import java.util.HashSet;
|
18
|
import java.util.List;
|
19
|
import java.util.Map;
|
20
|
import java.util.Set;
|
21
|
import java.util.UUID;
|
22
|
|
23
|
import org.apache.commons.lang.StringUtils;
|
24
|
import org.apache.log4j.Logger;
|
25
|
import org.springframework.stereotype.Component;
|
26
|
|
27
|
import eu.etaxonomy.cdm.common.CdmUtils;
|
28
|
import eu.etaxonomy.cdm.io.common.TdwgAreaProvider;
|
29
|
import eu.etaxonomy.cdm.io.excel.common.ExcelRowBase.SourceDataHolder;
|
30
|
import eu.etaxonomy.cdm.io.tcsrdf.TcsRdfTransformer;
|
31
|
import eu.etaxonomy.cdm.model.agent.Team;
|
32
|
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
|
33
|
import eu.etaxonomy.cdm.model.common.CdmBase;
|
34
|
import eu.etaxonomy.cdm.model.common.Extension;
|
35
|
import eu.etaxonomy.cdm.model.common.ExtensionType;
|
36
|
import eu.etaxonomy.cdm.model.common.Language;
|
37
|
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
|
38
|
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
|
39
|
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
|
40
|
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
|
41
|
import eu.etaxonomy.cdm.model.description.Distribution;
|
42
|
import eu.etaxonomy.cdm.model.description.Feature;
|
43
|
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
|
44
|
import eu.etaxonomy.cdm.model.description.TaxonDescription;
|
45
|
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
|
46
|
import eu.etaxonomy.cdm.model.description.TextData;
|
47
|
import eu.etaxonomy.cdm.model.location.NamedArea;
|
48
|
import eu.etaxonomy.cdm.model.media.Media;
|
49
|
import eu.etaxonomy.cdm.model.name.ITaxonNameBase;
|
50
|
import eu.etaxonomy.cdm.model.name.NameRelationshipType;
|
51
|
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
|
52
|
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
|
53
|
import eu.etaxonomy.cdm.model.name.NonViralName;
|
54
|
import eu.etaxonomy.cdm.model.name.Rank;
|
55
|
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
|
56
|
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
|
57
|
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
|
58
|
import eu.etaxonomy.cdm.model.reference.Reference;
|
59
|
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
|
60
|
import eu.etaxonomy.cdm.model.reference.ReferenceType;
|
61
|
import eu.etaxonomy.cdm.model.taxon.Classification;
|
62
|
import eu.etaxonomy.cdm.model.taxon.Synonym;
|
63
|
import eu.etaxonomy.cdm.model.taxon.SynonymType;
|
64
|
import eu.etaxonomy.cdm.model.taxon.Taxon;
|
65
|
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
|
66
|
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
|
67
|
import eu.etaxonomy.cdm.strategy.exceptions.StringNotParsableException;
|
68
|
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
|
69
|
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
|
70
|
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
|
71
|
|
72
|
/**
|
73
|
* @author a.babadshanjan
|
74
|
* @created 08.01.2009
|
75
|
*/
|
76
|
|
77
|
@Component
|
78
|
public class NormalExplicitImport extends TaxonExcelImporterBase {
|
79
|
private static final long serialVersionUID = 3642423349766191160L;
|
80
|
|
81
|
private static final Logger logger = Logger.getLogger(NormalExplicitImport.class);
|
82
|
|
83
|
public static Set<String> validMarkers = new HashSet<String>(Arrays.asList(new String[]{"", "valid", "accepted", "a", "v", "t", "!"}));
|
84
|
public static Set<String> synonymMarkers = new HashSet<String>(Arrays.asList(new String[]{"**","invalid", "synonym", "s", "i"}));
|
85
|
public static Set<String> nameStatusMarkers = new HashSet<String>(Arrays.asList(new String[]{"illegitimate", "nom. rej.", "nom. cons."}));
|
86
|
public static final UUID uuidRefExtension = UUID.fromString("a46533df-7a78-448f-9b80-36d087fbdf2a");
|
87
|
|
88
|
private static final Object NOM_ILLEG = "illegitimate";
|
89
|
private static final Object NOM_REJ = "nom. rej.";
|
90
|
private static final Object NOM_CONS = "nom. cons.";
|
91
|
|
92
|
|
93
|
/* (non-Javadoc)
|
94
|
* @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#analyzeSingleValue(eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase.KeyValue, eu.etaxonomy.cdm.io.excel.common.ExcelImportState)
|
95
|
*/
|
96
|
@Override
|
97
|
protected void analyzeSingleValue(KeyValue keyValue, TaxonExcelImportState state) {
|
98
|
|
99
|
NormalExplicitRow normalExplicitRow = state.getCurrentRow();
|
100
|
String key = keyValue.key;
|
101
|
String value = keyValue.value;
|
102
|
Integer index = keyValue.index;
|
103
|
if (((NormalExplicitImportConfigurator)state.getConfig()).getParentUUID() != null){
|
104
|
normalExplicitRow.setParentId("0");
|
105
|
}
|
106
|
|
107
|
key = key.replace(" ","");
|
108
|
if (key.equalsIgnoreCase(ID_COLUMN)) {
|
109
|
//String ivalue = floatString2IntValue(value);
|
110
|
normalExplicitRow.setId(value);
|
111
|
|
112
|
} else if(key.equalsIgnoreCase(PARENT_ID_COLUMN) ) {
|
113
|
//int ivalue = floatString2IntValue(value);
|
114
|
normalExplicitRow.setParentId(value);
|
115
|
|
116
|
} else if(key.equalsIgnoreCase(RANK_COLUMN)) {
|
117
|
normalExplicitRow.setRank(value);
|
118
|
|
119
|
} else if(key.trim().equalsIgnoreCase(SCIENTIFIC_NAME_COLUMN) || key.trim().equalsIgnoreCase(FULLNAME_COLUMN)) {
|
120
|
normalExplicitRow.setScientificName(value);
|
121
|
|
122
|
} else if(key.equalsIgnoreCase(AUTHOR_COLUMN)|| key.equalsIgnoreCase(AUTHORS_COLUMN)) {
|
123
|
normalExplicitRow.setAuthor(value);
|
124
|
}else if(key.equalsIgnoreCase(PUBLISHING_AUTHOR_COLUMN)) {
|
125
|
normalExplicitRow.setPublishingAuthor(value);
|
126
|
}else if(key.equalsIgnoreCase(BASIONYM_AUTHOR_COLUMN)) {
|
127
|
normalExplicitRow.setBasionymAuthor(value);
|
128
|
|
129
|
}else if(key.equalsIgnoreCase(BASIONYM_COLUMN)) {
|
130
|
normalExplicitRow.setBasionym(value);
|
131
|
}else if(key.trim().equalsIgnoreCase(NOMENCLATURAL_SYNONYM_COLUMN)) {
|
132
|
normalExplicitRow.setSynonym(value);
|
133
|
} else if(key.equalsIgnoreCase(REFERENCE_COLUMN) || key.equalsIgnoreCase(PUBLICATION_COLUMN)) {
|
134
|
normalExplicitRow.setReference(value);
|
135
|
|
136
|
} else if(key.equalsIgnoreCase(COLLATION_COLUMN)) {
|
137
|
normalExplicitRow.setCollation(value);
|
138
|
|
139
|
}else if(key.equalsIgnoreCase(NAMESTATUS_COLUMN)) {
|
140
|
normalExplicitRow.setNameStatus(value);
|
141
|
|
142
|
} else if(key.equalsIgnoreCase(VERNACULAR_NAME_COLUMN)) {
|
143
|
normalExplicitRow.setCommonName(value);
|
144
|
|
145
|
} else if(key.equalsIgnoreCase(LANGUAGE_COLUMN)) {
|
146
|
normalExplicitRow.setLanguage(value);
|
147
|
|
148
|
} else if(key.equalsIgnoreCase(TDWG_COLUMN) ) {
|
149
|
//TODO replace still necessary?
|
150
|
value = value.replace(".0", "");
|
151
|
normalExplicitRow.putDistribution(index, value);
|
152
|
|
153
|
} else if(key.equalsIgnoreCase(PROTOLOGUE_COLUMN)) {
|
154
|
normalExplicitRow.putProtologue(index, value);
|
155
|
|
156
|
} else if(key.equalsIgnoreCase(IMAGE_COLUMN)) {
|
157
|
normalExplicitRow.putImage(index, value);
|
158
|
|
159
|
} else if(key.equalsIgnoreCase(DATE_COLUMN) || key.equalsIgnoreCase(YEAR_COLUMN)|| key.equalsIgnoreCase(PUBLICATION_YEAR_COLUMN)) {
|
160
|
normalExplicitRow.setDate(value);
|
161
|
|
162
|
} else if(key.equalsIgnoreCase(FAMILY_COLUMN)) {
|
163
|
normalExplicitRow.setFamily(value);
|
164
|
} else if(key.equalsIgnoreCase(INFRA_FAMILY_COLUMN)) {
|
165
|
normalExplicitRow.setInfraFamily(value);
|
166
|
}else if(key.equalsIgnoreCase(GENUS_COLUMN)) {
|
167
|
normalExplicitRow.setGenus(value);
|
168
|
}else if(key.trim().equalsIgnoreCase(INFRA_GENUS_COLUMN.trim())) {
|
169
|
normalExplicitRow.setInfraGenus(value);
|
170
|
}else if(key.equalsIgnoreCase(SPECIES_COLUMN)) {
|
171
|
normalExplicitRow.setSpecies(value);
|
172
|
}else if(key.equalsIgnoreCase(INFRA_SPECIES_COLUMN)) {
|
173
|
normalExplicitRow.setInfraSpecies(value);
|
174
|
} else if (key.equalsIgnoreCase(VERSION_COLUMN)){
|
175
|
normalExplicitRow.setVersion(value);
|
176
|
}
|
177
|
|
178
|
|
179
|
|
180
|
|
181
|
else if(key.equalsIgnoreCase("!")) {
|
182
|
//! = Legitimate, * = Illegitimate, ** = Invalid, *** = nom. rej., !! = nom. cons.
|
183
|
if (value.equals("!")){
|
184
|
normalExplicitRow.setNameStatus("accepted");
|
185
|
} else if (value.equals("*")){
|
186
|
normalExplicitRow.setNameStatus("illegitimate");
|
187
|
} else if (value.equals("**")){
|
188
|
normalExplicitRow.setNameStatus("invalid");
|
189
|
} else if (value.equals("***")){
|
190
|
normalExplicitRow.setNameStatus("nom. rej.");
|
191
|
} else if (value.equals("!!")){
|
192
|
normalExplicitRow.setNameStatus("nom. cons.");
|
193
|
} else{
|
194
|
normalExplicitRow.setNameStatus("accepted");
|
195
|
}
|
196
|
}else {
|
197
|
if (analyzeFeatures(state, keyValue)){
|
198
|
|
199
|
}else{
|
200
|
String message = "Unexpected column header " + key;
|
201
|
fireWarningEvent(message, state, 10);
|
202
|
state.setUnsuccessfull();
|
203
|
//logger.error(message);
|
204
|
}
|
205
|
}
|
206
|
return;
|
207
|
}
|
208
|
|
209
|
|
210
|
/**
|
211
|
* Create base taxa and add all information attached to it's name.
|
212
|
*/
|
213
|
@Override
|
214
|
protected void firstPass(TaxonExcelImportState state) {
|
215
|
|
216
|
// if (1==1){
|
217
|
// return;
|
218
|
// }
|
219
|
// System.out.println("FP:" + state.getCurrentLine());
|
220
|
Rank rank = null;
|
221
|
NormalExplicitRow taxonDataHolder = state.getCurrentRow();
|
222
|
|
223
|
String rankStr = taxonDataHolder.getRank();
|
224
|
String taxonNameStr = taxonDataHolder.getScientificName();
|
225
|
String authorStr = taxonDataHolder.getAuthor();
|
226
|
String publishingAuthor= taxonDataHolder.getPublishingAuthor();
|
227
|
String basionymAuthor = taxonDataHolder.getBasionymAuthor();
|
228
|
|
229
|
String referenceStr = taxonDataHolder.getReference();
|
230
|
String nameStatus = taxonDataHolder.getNameStatus();
|
231
|
String familyNameStr = taxonDataHolder.getFamily();
|
232
|
String infraFamilyNameStr = taxonDataHolder.getInfraFamily();
|
233
|
String genusNameStr = taxonDataHolder.getGenus();
|
234
|
String infraGenusNameStr = taxonDataHolder.getInfraGenus();
|
235
|
String speciesNameStr = taxonDataHolder.getSpecies();
|
236
|
String infraSpeciesNameStr = taxonDataHolder.getInfraSpecies();
|
237
|
|
238
|
String version = taxonDataHolder.getVersion();
|
239
|
|
240
|
|
241
|
|
242
|
|
243
|
String dateStr = taxonDataHolder.getDate();
|
244
|
String id = taxonDataHolder.getId();
|
245
|
UUID cdmUuid = taxonDataHolder.getCdmUuid();
|
246
|
|
247
|
TaxonBase<?> taxonBase = null;
|
248
|
if (cdmUuid != null){
|
249
|
taxonBase = getTaxonService().find(cdmUuid);
|
250
|
}else{
|
251
|
if (StringUtils.isNotBlank(taxonNameStr)) {
|
252
|
|
253
|
// Rank
|
254
|
try {
|
255
|
if (!StringUtils.isBlank(rankStr)) {
|
256
|
rank = Rank.getRankByNameOrIdInVoc(rankStr);
|
257
|
}
|
258
|
} catch (UnknownCdmTypeException ex) {
|
259
|
try {
|
260
|
rank = Rank.getRankByEnglishName(rankStr, state.getConfig().getNomenclaturalCode(), false);
|
261
|
} catch (UnknownCdmTypeException e) {
|
262
|
try {
|
263
|
rank = TcsRdfTransformer.rankString2Rank(rankStr);
|
264
|
} catch (UnknownCdmTypeException e1) {
|
265
|
// TODO Auto-generated catch block
|
266
|
e1.printStackTrace();
|
267
|
}
|
268
|
|
269
|
}
|
270
|
}
|
271
|
|
272
|
//taxon
|
273
|
taxonBase = createTaxon(state, rank, taxonNameStr, authorStr, publishingAuthor, basionymAuthor, referenceStr, dateStr, nameStatus);
|
274
|
}else{
|
275
|
return;
|
276
|
}
|
277
|
}
|
278
|
if (taxonBase == null){
|
279
|
String message = "Taxon is already in DB. Record will not be handled";
|
280
|
fireWarningEvent(message, "Record: " + state.getCurrentLine(), 6);
|
281
|
logger.warn(message);
|
282
|
//state.setUnsuccessfull();
|
283
|
return;
|
284
|
}
|
285
|
|
286
|
//protologue
|
287
|
for (String protologue : taxonDataHolder.getProtologues()){
|
288
|
TextData textData = TextData.NewInstance(Feature.PROTOLOGUE());
|
289
|
this.getNameDescription(taxonBase.getName()).addElement(textData);
|
290
|
URI uri;
|
291
|
try {
|
292
|
uri = new URI(protologue);
|
293
|
textData.addMedia(Media.NewInstance(uri, null, null, null));
|
294
|
} catch (URISyntaxException e) {
|
295
|
String warning = "URISyntaxException when trying to convert to URI: " + protologue;
|
296
|
logger.error(warning);
|
297
|
state.setUnsuccessfull();
|
298
|
}
|
299
|
}
|
300
|
|
301
|
state.putTaxon(id, taxonBase);
|
302
|
taxonBase = getTaxonService().save(taxonBase);
|
303
|
taxonDataHolder.setCdmUuid(taxonBase.getUuid());
|
304
|
return;
|
305
|
}
|
306
|
|
307
|
|
308
|
|
309
|
/**
|
310
|
* Stores parent-child, synonym and common name relationships.
|
311
|
* Adds all taxon related descriptive information (this is not done in the first pass
|
312
|
* because the information may also be attached to a synonym).
|
313
|
*/
|
314
|
@Override
|
315
|
protected void secondPass(TaxonExcelImportState state) {
|
316
|
if (logger.isDebugEnabled()){logger.debug(state.getCurrentLine());}
|
317
|
try {
|
318
|
NormalExplicitRow taxonDataHolder = state.getCurrentRow();
|
319
|
String taxonNameStr = taxonDataHolder.getScientificName();
|
320
|
String nameStatus = taxonDataHolder.getNameStatus();
|
321
|
String commonNameStr = taxonDataHolder.getCommonName();
|
322
|
|
323
|
String synonymNameStr = taxonDataHolder.getSynonym();
|
324
|
String basionymNameStr = taxonDataHolder.getBasionym();
|
325
|
|
326
|
String parentId = taxonDataHolder.getParentId();
|
327
|
String childId = taxonDataHolder.getId();
|
328
|
UUID cdmUuid = taxonDataHolder.getCdmUuid();
|
329
|
Taxon acceptedTaxon = null;
|
330
|
TaxonNameBase<?,?> nameUsedInSource = null;
|
331
|
TaxonBase<?> taxonBase = null;
|
332
|
Taxon parentTaxon = null;
|
333
|
|
334
|
if (cdmUuid != null){
|
335
|
taxonBase = getTaxonService().find(cdmUuid);
|
336
|
if (taxonBase != null ){
|
337
|
acceptedTaxon = getAcceptedTaxon(taxonBase);
|
338
|
nameUsedInSource = taxonBase.getName();
|
339
|
}
|
340
|
} else{
|
341
|
taxonBase = state.getTaxonBase(childId);
|
342
|
|
343
|
if (parentId == "0" && state.getParent() == null){
|
344
|
parentTaxon =(Taxon) getTaxonService().load(((NormalExplicitImportConfigurator)state.getConfig()).getParentUUID());
|
345
|
state.setParent(parentTaxon);
|
346
|
}else if (parentId != "0"){
|
347
|
parentTaxon = CdmBase.deproxy(state.getTaxonBase(parentId), Taxon.class);
|
348
|
} else if (state.getParent() != null){
|
349
|
parentTaxon = state.getParent();
|
350
|
}
|
351
|
if (taxonBase != null ){
|
352
|
acceptedTaxon = getAcceptedTaxon(taxonBase);
|
353
|
if (synonymNameStr != null){
|
354
|
Synonym syn = createSynonym(state,taxonBase,synonymNameStr);
|
355
|
acceptedTaxon.addSynonym(syn, SynonymType.HETEROTYPIC_SYNONYM_OF());
|
356
|
}
|
357
|
if (basionymNameStr != null){
|
358
|
Synonym syn = createSynonym(state,taxonBase,basionymNameStr);
|
359
|
acceptedTaxon.addSynonym(syn, SynonymType.HOMOTYPIC_SYNONYM_OF());
|
360
|
syn.getName().addRelationshipToName(acceptedTaxon.getName(), NameRelationshipType.BASIONYM(), null);
|
361
|
}
|
362
|
nameUsedInSource = taxonBase.getName();
|
363
|
|
364
|
//TODO error handling for class cast
|
365
|
|
366
|
|
367
|
nameUsedInSource = taxonBase.getName();
|
368
|
nameStatus = CdmUtils.Nz(nameStatus).trim().toLowerCase();
|
369
|
if (validMarkers.contains(nameStatus)){
|
370
|
Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
|
371
|
acceptedTaxon = taxon;
|
372
|
// Add the parent relationship
|
373
|
//if (state.getCurrentRow().getParentId() != 0) {
|
374
|
MergeResult result = null;
|
375
|
if (parentTaxon != null) {
|
376
|
//Taxon taxon = (Taxon)state.getTaxonBase(childId);
|
377
|
|
378
|
Reference sourceRef = state.getConfig().getSourceReference();
|
379
|
String microCitation = null;
|
380
|
Taxon childTaxon = taxon;
|
381
|
makeParent(state, parentTaxon, childTaxon, sourceRef, microCitation);
|
382
|
getTaxonService().saveOrUpdate(childTaxon);
|
383
|
state.putTaxon(parentId, parentTaxon);
|
384
|
} else {
|
385
|
String message = "Taxonomic parent not found for " + taxonNameStr;
|
386
|
logger.warn(message);
|
387
|
fireWarningEvent(message, state, 6);
|
388
|
//state.setUnsuccessfull();
|
389
|
}
|
390
|
// }else{
|
391
|
// //do nothing (parent == 0) no parent exists
|
392
|
// }
|
393
|
}else if (synonymMarkers.contains(nameStatus)){
|
394
|
//add synonym relationship
|
395
|
acceptedTaxon = parentTaxon;
|
396
|
try {
|
397
|
Synonym synonym = CdmBase.deproxy(taxonBase,Synonym.class);
|
398
|
if (acceptedTaxon == null){
|
399
|
String message = "Accepted/valid taxon could not be found. Please check referential integrity.";
|
400
|
fireWarningEvent(message, state, 8);
|
401
|
}else{
|
402
|
if (parentId != "0"){
|
403
|
//if no relation was defined in file skip relationship creation
|
404
|
acceptedTaxon.addSynonym(synonym, SynonymType.SYNONYM_OF());
|
405
|
getTaxonService().saveOrUpdate(acceptedTaxon);
|
406
|
}
|
407
|
}
|
408
|
} catch (Exception e) {
|
409
|
String message = "Unhandled exception (%s) occurred during synonym import/update";
|
410
|
message = String.format(message, e.getMessage());
|
411
|
fireWarningEvent(message, state, 10);
|
412
|
state.setUnsuccessfull();
|
413
|
}
|
414
|
|
415
|
}else{
|
416
|
if (parentTaxon != null) {
|
417
|
Taxon taxon = (Taxon)state.getTaxonBase(childId);
|
418
|
|
419
|
Reference sourceRef = state.getConfig().getSourceReference();
|
420
|
String microCitation = null;
|
421
|
Taxon childTaxon = taxon;
|
422
|
makeParent(state, parentTaxon, childTaxon, sourceRef, microCitation);
|
423
|
getTaxonService().saveOrUpdate(parentTaxon);
|
424
|
state.putTaxon(parentId, parentTaxon);
|
425
|
} else {
|
426
|
String message = "Taxonomic parent not found for " + taxonNameStr;
|
427
|
logger.warn(message);
|
428
|
fireWarningEvent(message, state, 6);
|
429
|
//state.setUnsuccessfull();
|
430
|
}
|
431
|
}
|
432
|
|
433
|
|
434
|
}
|
435
|
if (StringUtils.isBlank(taxonNameStr) && acceptedTaxon == null) {
|
436
|
acceptedTaxon = parentTaxon;
|
437
|
nameUsedInSource = null;
|
438
|
}
|
439
|
}
|
440
|
if (acceptedTaxon == null && (StringUtils.isNotBlank(commonNameStr) ||taxonDataHolder.getFeatures().size() > 0 )){
|
441
|
String message = "Accepted taxon could not be found. Can't add additional data (common names, descriptive data, ...) to taxon";
|
442
|
fireWarningEvent(message, state, 6);
|
443
|
}else{
|
444
|
//common names
|
445
|
if (StringUtils.isNotBlank(commonNameStr)){ // add common name to taxon
|
446
|
handleCommonName(state, taxonNameStr, commonNameStr, acceptedTaxon);
|
447
|
}
|
448
|
|
449
|
|
450
|
//media
|
451
|
for (String imageUrl : taxonDataHolder.getImages()){
|
452
|
TaxonDescription td = acceptedTaxon.getImageGallery(true);
|
453
|
DescriptionElementBase mediaHolder;
|
454
|
if (td.getElements().size() != 0){
|
455
|
mediaHolder = td.getElements().iterator().next();
|
456
|
}else{
|
457
|
mediaHolder = TextData.NewInstance(Feature.IMAGE());
|
458
|
td.addElement(mediaHolder);
|
459
|
}
|
460
|
try {
|
461
|
Media media = getImageMedia(imageUrl, READ_MEDIA_DATA);
|
462
|
mediaHolder.addMedia(media);
|
463
|
} catch (MalformedURLException e) {
|
464
|
logger.warn("Can't add media: " + e.getMessage());
|
465
|
state.setUnsuccessfull();
|
466
|
}
|
467
|
}
|
468
|
|
469
|
//tdwg label
|
470
|
for (String tdwg : taxonDataHolder.getDistributions()){
|
471
|
TaxonDescription td = this.getTaxonDescription(acceptedTaxon, state.getConfig().getSourceReference() ,false, true);
|
472
|
NamedArea area = TdwgAreaProvider.getAreaByTdwgAbbreviation(tdwg);
|
473
|
if (area == null){
|
474
|
area = TdwgAreaProvider.getAreaByTdwgLabel(tdwg);
|
475
|
}
|
476
|
if (area != null){
|
477
|
Distribution distribution = Distribution.NewInstance(area, PresenceAbsenceTerm.PRESENT());
|
478
|
td.addElement(distribution);
|
479
|
}else{
|
480
|
String message = "TDWG area could not be recognized: " + tdwg;
|
481
|
logger.warn(message);
|
482
|
state.setUnsuccessfull();
|
483
|
}
|
484
|
}
|
485
|
|
486
|
//features
|
487
|
handleFeatures(state, taxonDataHolder, acceptedTaxon, nameUsedInSource);
|
488
|
}
|
489
|
} catch (Exception e) {
|
490
|
e.printStackTrace();
|
491
|
}
|
492
|
return;
|
493
|
}
|
494
|
|
495
|
|
496
|
/**
|
497
|
* @param state
|
498
|
* @param taxonBase
|
499
|
* @param synonymNameStr
|
500
|
*/
|
501
|
private Synonym createSynonym(TaxonExcelImportState state, TaxonBase<?> taxonBase, String synonymNameStr) {
|
502
|
NomenclaturalCode nc = state.getConfig().getNomenclaturalCode();
|
503
|
ITaxonNameBase name = null;
|
504
|
if (nc.isKindOf(NomenclaturalCode.ICZN)){
|
505
|
name = TaxonNameFactory.NewZoologicalInstance(taxonBase.getName().getRank());
|
506
|
}else if (nc.isKindOf(NomenclaturalCode.ICNAFP)){
|
507
|
name = TaxonNameFactory.NewBotanicalInstance(taxonBase.getName().getRank());
|
508
|
} else{
|
509
|
name = TaxonNameFactory.NewNonViralInstance(taxonBase.getName().getRank());
|
510
|
}
|
511
|
name.setTitleCache(synonymNameStr, true);
|
512
|
if (name != null){
|
513
|
return Synonym.NewInstance(name, null);
|
514
|
}
|
515
|
logger.debug("The nomenclatural code is not supported.");
|
516
|
return null;
|
517
|
}
|
518
|
|
519
|
|
520
|
/**
|
521
|
* @param state
|
522
|
* @param taxonDataHolder
|
523
|
* @param acceptedTaxon
|
524
|
*/
|
525
|
private void handleFeatures(TaxonExcelImportState state, NormalExplicitRow taxonDataHolder, Taxon acceptedTaxon, TaxonNameBase nameUsedInSource) {
|
526
|
//feature
|
527
|
for (UUID featureUuid : taxonDataHolder.getFeatures()){
|
528
|
Feature feature = getFeature(state, featureUuid);
|
529
|
List<String> textList = taxonDataHolder.getFeatureTexts(featureUuid);
|
530
|
List<String> languageList = taxonDataHolder.getFeatureLanguages(featureUuid);
|
531
|
|
532
|
for (int i = 0; i < textList.size(); i++){
|
533
|
String featureText = textList.get(i);
|
534
|
String featureLanguage = languageList == null ? null :languageList.get(i);
|
535
|
Language language = getFeatureLanguage(featureLanguage, state);
|
536
|
//TODO
|
537
|
TaxonDescription td = this.getTaxonDescription(acceptedTaxon, state.getConfig().getSourceReference() ,false, true);
|
538
|
TextData textData = TextData.NewInstance(feature);
|
539
|
textData.putText(language, featureText);
|
540
|
td.addElement(textData);
|
541
|
|
542
|
SourceDataHolder sourceDataHolder = taxonDataHolder.getFeatureTextReferences(featureUuid, i);
|
543
|
List<Map<SourceType, String>> sourceList = sourceDataHolder.getSources();
|
544
|
for (Map<SourceType, String> sourceMap : sourceList){
|
545
|
|
546
|
//ref
|
547
|
Reference ref = ReferenceFactory.newGeneric();
|
548
|
boolean refExists = false; //in case none of the ref fields exists, the ref should not be added
|
549
|
for (SourceType type : sourceMap.keySet()){
|
550
|
String value = sourceMap.get(type);
|
551
|
if (type.equals(SourceType.Author)){
|
552
|
TeamOrPersonBase<?> author = getAuthorAccordingToConfig(value, state);
|
553
|
ref.setAuthorship(author);
|
554
|
}else if (type.equals(SourceType.Title)) {
|
555
|
ref.setTitle(value);
|
556
|
}else if (type.equals(SourceType.Year)) {
|
557
|
ref.setDatePublished(TimePeriodParser.parseString(value));
|
558
|
}else if (type.equals(SourceType.RefExtension)) {
|
559
|
ExtensionType extensionType = getExtensionType(state, uuidRefExtension, "RefExtension", "Reference Extension", "RefExt.");
|
560
|
Extension extension = Extension.NewInstance(ref, value, extensionType);
|
561
|
}
|
562
|
refExists = true;
|
563
|
}
|
564
|
DescriptionElementSource source = DescriptionElementSource.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
|
565
|
if (refExists){
|
566
|
ref = getReferenceAccordingToConfig(ref, state);
|
567
|
source.setCitation(ref);
|
568
|
source.setNameUsedInSource(nameUsedInSource);
|
569
|
}
|
570
|
textData.addSource(source);
|
571
|
}
|
572
|
}
|
573
|
}
|
574
|
}
|
575
|
|
576
|
private final Map<String, UUID> referenceMapping = new HashMap<String, UUID>();
|
577
|
private final Map<UUID, Reference> referenceStore = new HashMap<UUID, Reference>();
|
578
|
|
579
|
private Reference getReferenceAccordingToConfig(Reference value, TaxonExcelImportState state) {
|
580
|
Reference result = null;
|
581
|
String titleCache = value.getTitleCache();
|
582
|
UUID referenceUuid = referenceMapping.get(titleCache);
|
583
|
if (referenceUuid != null){
|
584
|
result = referenceStore.get(referenceUuid);
|
585
|
}
|
586
|
if (result == null){
|
587
|
result = value;
|
588
|
referenceStore.put(result.getUuid(), result);
|
589
|
}
|
590
|
if (referenceUuid == null){
|
591
|
referenceMapping.put(titleCache, result.getUuid());
|
592
|
}
|
593
|
return result;
|
594
|
}
|
595
|
|
596
|
|
597
|
private final Map<String, UUID> authorMapping = new HashMap<String, UUID>();
|
598
|
private final Map<UUID, TeamOrPersonBase> authorStore = new HashMap<UUID, TeamOrPersonBase>();
|
599
|
|
600
|
private TeamOrPersonBase<?> getAuthorAccordingToConfig(String value, TaxonExcelImportState state) {
|
601
|
TeamOrPersonBase<?> result = null;
|
602
|
UUID authorUuid = authorMapping.get(value);
|
603
|
if (authorUuid != null){
|
604
|
result = authorStore.get(authorUuid);
|
605
|
}
|
606
|
if (result == null){
|
607
|
//TODO parsing
|
608
|
TeamOrPersonBase<?> author = Team.NewInstance();
|
609
|
author.setTitleCache(value, true);
|
610
|
result = author;
|
611
|
authorStore.put(result.getUuid(), result);
|
612
|
}
|
613
|
if (authorUuid == null){
|
614
|
authorMapping.put(value, result.getUuid());
|
615
|
}
|
616
|
return result;
|
617
|
}
|
618
|
|
619
|
|
620
|
private final Map<String, UUID> languageMapping = new HashMap<String, UUID>();
|
621
|
|
622
|
private Language getFeatureLanguage(String featureLanguage, TaxonExcelImportState state) {
|
623
|
if (StringUtils.isBlank(featureLanguage)){
|
624
|
return null;
|
625
|
}
|
626
|
UUID languageUuid = languageMapping.get(featureLanguage);
|
627
|
if (languageUuid == null){
|
628
|
Language result = getTermService().getLanguageByIso(featureLanguage);
|
629
|
languageUuid = result.getUuid();
|
630
|
languageMapping.put(featureLanguage, languageUuid);
|
631
|
}
|
632
|
Language result = getLanguage(state, languageUuid, null, null, null);
|
633
|
return result;
|
634
|
}
|
635
|
|
636
|
|
637
|
/**
|
638
|
* @param state
|
639
|
* @param taxonNameStr
|
640
|
* @param commonNameStr
|
641
|
* @param parentId
|
642
|
*/
|
643
|
private void handleCommonName(TaxonExcelImportState state,
|
644
|
String taxonNameStr, String commonNameStr, Taxon acceptedTaxon) {
|
645
|
Language language = getTermService().getLanguageByIso(state.getCurrentRow().getLanguage());
|
646
|
if (language == null && CdmUtils.isNotEmpty(state.getCurrentRow().getLanguage()) ){
|
647
|
String error ="Language is null but shouldn't";
|
648
|
logger.error(error);
|
649
|
throw new IllegalArgumentException(error);
|
650
|
}
|
651
|
CommonTaxonName commonTaxonName = CommonTaxonName.NewInstance(commonNameStr, language);
|
652
|
try {
|
653
|
TaxonDescription taxonDescription = getTaxonDescription(acceptedTaxon, false, true);
|
654
|
taxonDescription.addElement(commonTaxonName);
|
655
|
logger.info("Common name " + commonNameStr + " added to " + acceptedTaxon.getTitleCache());
|
656
|
} catch (ClassCastException ex) {
|
657
|
logger.error(taxonNameStr + " is not a taxon instance.");
|
658
|
}
|
659
|
}
|
660
|
|
661
|
|
662
|
/**
|
663
|
* @param state
|
664
|
* @param rank
|
665
|
* @param taxonNameStr
|
666
|
* @param authorStr
|
667
|
* @param nameStatus
|
668
|
* @param nameStatus2
|
669
|
* @return
|
670
|
*/
|
671
|
private TaxonBase createTaxon(TaxonExcelImportState state, Rank rank,
|
672
|
String familyNameStr, String infraFamilyNameStr, String genusNameStr, String infraGenusNameStr, String speciesNameStr, String infraSpeciesNameStr, String authorStr, String publishingAuthorStr, String basionymAuthorStr,String reference, String date, String nameStatus) {
|
673
|
// Create the taxon name object depending on the setting of the nomenclatural code
|
674
|
// in the configurator (botanical code, zoological code, etc.)
|
675
|
|
676
|
NomenclaturalCode nc = getConfigurator().getNomenclaturalCode();
|
677
|
|
678
|
TaxonBase taxonBase;
|
679
|
String nameCache = null;
|
680
|
if (rank == null){
|
681
|
System.err.println("bla");
|
682
|
}
|
683
|
if (rank.isGenus()){
|
684
|
nameCache =genusNameStr;
|
685
|
} else if (rank.isInfraGeneric()){
|
686
|
nameCache =CdmUtils.concat(" " +rank.getIdInVocabulary() + " ",genusNameStr,infraGenusNameStr);
|
687
|
|
688
|
} else if (rank.isSpecies()){
|
689
|
nameCache = CdmUtils.concat(" ", genusNameStr,speciesNameStr);
|
690
|
} else if (rank.isInfraSpecific()){
|
691
|
nameCache = CdmUtils.concat(" " +rank.getIdInVocabulary() + " ",genusNameStr,infraGenusNameStr);
|
692
|
}
|
693
|
if (! synonymMarkers.contains(nameStatus) && state.getConfig().isReuseExistingTaxaWhenPossible()){
|
694
|
taxonBase = getTaxonService().findBestMatchingTaxon(nameCache);
|
695
|
}else{
|
696
|
taxonBase = getTaxonService().findBestMatchingSynonym(nameCache);
|
697
|
if (taxonBase != null){
|
698
|
logger.info("Matching taxon/synonym found for " + nameCache);
|
699
|
}
|
700
|
}
|
701
|
if (taxonBase != null){
|
702
|
logger.info("Matching taxon/synonym found for " + nameCache);
|
703
|
return null;
|
704
|
}else {
|
705
|
taxonBase = createTaxon(state, rank, nameCache, authorStr, publishingAuthorStr, basionymAuthorStr, reference, date, nameStatus, nc);
|
706
|
}
|
707
|
return taxonBase;
|
708
|
}
|
709
|
|
710
|
/**
|
711
|
* @param state
|
712
|
* @param rank
|
713
|
* @param taxonNameStr
|
714
|
* @param authorStr
|
715
|
* @param nameStatus
|
716
|
* @param nameStatus2
|
717
|
* @return
|
718
|
*/
|
719
|
private TaxonBase createTaxon(TaxonExcelImportState state, Rank rank,
|
720
|
String taxonNameStr, String authorStr, String publishingAuthorStr, String basionymAuthorStr,String reference, String date, String nameStatus) {
|
721
|
// Create the taxon name object depending on the setting of the nomenclatural code
|
722
|
// in the configurator (botanical code, zoological code, etc.)
|
723
|
if (StringUtils.isBlank(taxonNameStr)){
|
724
|
return null;
|
725
|
}
|
726
|
NomenclaturalCode nc = getConfigurator().getNomenclaturalCode();
|
727
|
|
728
|
TaxonBase taxonBase = null;
|
729
|
|
730
|
String titleCache = CdmUtils.concat(" ", taxonNameStr, authorStr);
|
731
|
if (! synonymMarkers.contains(nameStatus) && state.getConfig().isReuseExistingTaxaWhenPossible()){
|
732
|
titleCache = CdmUtils.concat(" ", taxonNameStr, authorStr);
|
733
|
taxonBase = getTaxonService().findBestMatchingTaxon(titleCache);
|
734
|
}else if ( state.getConfig().isReuseExistingTaxaWhenPossible()){
|
735
|
taxonBase = getTaxonService().findBestMatchingSynonym(titleCache);
|
736
|
if (taxonBase != null){
|
737
|
logger.info("Matching taxon/synonym found for " + titleCache);
|
738
|
}
|
739
|
}
|
740
|
if (taxonBase != null){
|
741
|
logger.info("Matching taxon/synonym found for " + titleCache);
|
742
|
return null;
|
743
|
}else {
|
744
|
taxonBase = createTaxon(state, rank, taxonNameStr, authorStr, publishingAuthorStr, basionymAuthorStr, reference, date, nameStatus, nc);
|
745
|
}
|
746
|
return taxonBase;
|
747
|
}
|
748
|
|
749
|
|
750
|
|
751
|
/**
|
752
|
* @param state
|
753
|
* @param rank
|
754
|
* @param taxonNameStr
|
755
|
* @param authorStr
|
756
|
* @param nameStatus
|
757
|
* @param nameStatus2
|
758
|
* @param nc
|
759
|
* @return
|
760
|
*/
|
761
|
private TaxonBase<?> createTaxon(TaxonExcelImportState state, Rank rank, String taxonNameStr,
|
762
|
String authorStr, String publishingAutorStr, String basionymAuthor, String reference, String date, String nameStatus, NomenclaturalCode nc) {
|
763
|
TaxonBase<?> taxonBase;
|
764
|
NonViralName<?> taxonNameBase = null;
|
765
|
if (nc == NomenclaturalCode.ICVCN){
|
766
|
logger.warn("ICVCN not yet supported");
|
767
|
|
768
|
}else{
|
769
|
//String taxonNameStr = titleCache.substring(0, titleCache.indexOf(authorStr));
|
770
|
taxonNameBase =(NonViralName<?>) nc.getNewTaxonNameInstance(rank);
|
771
|
NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
|
772
|
taxonNameBase = parser.parseFullName(taxonNameStr, nc, rank);
|
773
|
|
774
|
if (! taxonNameBase.getNameCache().equals(taxonNameStr)){
|
775
|
taxonNameBase.setNameCache(taxonNameStr, true);
|
776
|
}
|
777
|
|
778
|
// Create the author
|
779
|
if (StringUtils.isNotBlank(authorStr)) {
|
780
|
try {
|
781
|
parser.parseAuthors(taxonNameBase, authorStr);
|
782
|
} catch (StringNotParsableException e) {
|
783
|
taxonNameBase.setAuthorshipCache(authorStr);
|
784
|
}
|
785
|
}
|
786
|
if (StringUtils.isNotBlank(reference)) {
|
787
|
|
788
|
INomenclaturalReference ref = parser.parseReferenceTitle(reference, date, true);
|
789
|
if (ref.getAuthorship() == null){
|
790
|
ref.setAuthorship(taxonNameBase.getCombinationAuthorship());
|
791
|
}
|
792
|
|
793
|
if (ref.getAbbrevTitle() == null && !ref.isOfType(ReferenceType.Article)) {
|
794
|
ref.setAbbrevTitle(reference);
|
795
|
ref.setProtectedAbbrevTitleCache(false);
|
796
|
}
|
797
|
|
798
|
ref.setProtectedTitleCache(false);
|
799
|
|
800
|
taxonNameBase.setNomenclaturalReference(ref);
|
801
|
taxonNameBase.setNomenclaturalMicroReference(state.getCurrentRow().getCollation());
|
802
|
}
|
803
|
}
|
804
|
|
805
|
//Create the taxon
|
806
|
Reference sec = state.getConfig().getSourceReference();
|
807
|
// Create the status
|
808
|
nameStatus = CdmUtils.Nz(nameStatus).trim().toLowerCase();
|
809
|
if (validMarkers.contains(nameStatus)){
|
810
|
taxonBase = Taxon.NewInstance(taxonNameBase, sec);
|
811
|
}else if (synonymMarkers.contains(nameStatus)){
|
812
|
taxonBase = Synonym.NewInstance(taxonNameBase, sec);
|
813
|
}else {
|
814
|
Taxon taxon = Taxon.NewInstance(taxonNameBase, sec);
|
815
|
if (nameStatusMarkers.contains(nameStatus)){
|
816
|
if (nameStatus.equals(NOM_ILLEG)){
|
817
|
taxonNameBase.addStatus(NomenclaturalStatusType.ILLEGITIMATE(), null, null);
|
818
|
} else if (nameStatus.equals(NOM_REJ)){
|
819
|
taxonNameBase.addStatus(NomenclaturalStatusType.REJECTED(), null, null);
|
820
|
} else if (nameStatus.equals(NOM_CONS)){
|
821
|
taxonNameBase.addStatus(NomenclaturalStatusType.CONSERVED(), null, null);
|
822
|
}
|
823
|
}else{
|
824
|
taxon.setTaxonStatusUnknown(true);
|
825
|
}
|
826
|
taxonBase = taxon;
|
827
|
}
|
828
|
taxonBase.getName().addSource(OriginalSourceType.Import, "urn:lsid:ipni.org:names:"+ state.getCurrentRow().getId()+":"+state.getCurrentRow().getVersion(),"TaxonName" ,null, null);
|
829
|
taxonBase.addSource(OriginalSourceType.Import, "urn:lsid:ipni.org:names:"+ state.getCurrentRow().getId()+":"+state.getCurrentRow().getVersion(),"TaxonName" ,null, null);
|
830
|
|
831
|
return taxonBase;
|
832
|
}
|
833
|
|
834
|
/**
|
835
|
* @param taxon
|
836
|
* @return
|
837
|
*/
|
838
|
//TODO implementation must be improved when matching of taxon names with existing names is implemented
|
839
|
//=> the assumption that the only description is the description added by this import
|
840
|
//is wrong then
|
841
|
private TaxonNameDescription getNameDescription(TaxonNameBase<?,?> name) {
|
842
|
Set<TaxonNameDescription> descriptions = name.getDescriptions();
|
843
|
if (descriptions.size()>1){
|
844
|
throw new IllegalStateException("Implementation does not yet support names with multiple descriptions");
|
845
|
}else if (descriptions.size()==1){
|
846
|
return descriptions.iterator().next();
|
847
|
}else{
|
848
|
return TaxonNameDescription.NewInstance(name);
|
849
|
}
|
850
|
}
|
851
|
|
852
|
private void makeParent(TaxonExcelImportState state, Taxon parentTaxon, Taxon childTaxon, Reference citation, String microCitation){
|
853
|
Reference sec = state.getConfig().getSourceReference();
|
854
|
|
855
|
// Reference sec = parentTaxon.getSec();
|
856
|
Classification tree = state.getClassification();
|
857
|
if (tree == null){
|
858
|
//tree = makeTree(state, sec);
|
859
|
if (state.getConfig().getClassificationUuid() != null){
|
860
|
tree = getClassificationService().load(state.getConfig().getClassificationUuid());
|
861
|
state.setClassification(tree);
|
862
|
}
|
863
|
if (tree == null){
|
864
|
tree = makeTree(state, sec);
|
865
|
getClassificationService().save(tree);
|
866
|
state.setClassification(tree);
|
867
|
}
|
868
|
}
|
869
|
if (sec.equals(childTaxon.getSec())){
|
870
|
boolean success = (null != tree.addParentChild(parentTaxon, childTaxon, citation, microCitation));
|
871
|
if (success == false){
|
872
|
state.setUnsuccessfull();
|
873
|
}
|
874
|
}else{
|
875
|
logger.warn("No relationship added for child " + childTaxon.getTitleCache());
|
876
|
}
|
877
|
return;
|
878
|
}
|
879
|
|
880
|
|
881
|
/* (non-Javadoc)
|
882
|
* @see eu.etaxonomy.cdm.io.excel.common.ExcelTaxonOrSpecimenImportBase#createDataHolderRow()
|
883
|
*/
|
884
|
@Override
|
885
|
protected NormalExplicitRow createDataHolderRow() {
|
886
|
return new NormalExplicitRow();
|
887
|
}
|
888
|
|
889
|
|
890
|
|
891
|
/* (non-Javadoc)
|
892
|
* @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
|
893
|
*/
|
894
|
@Override
|
895
|
protected boolean doCheck(TaxonExcelImportState state) {
|
896
|
logger.warn("DoCheck not yet implemented for NormalExplicitImport");
|
897
|
return true;
|
898
|
}
|
899
|
|
900
|
/* (non-Javadoc)
|
901
|
* @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
|
902
|
*/
|
903
|
@Override
|
904
|
protected boolean isIgnore(TaxonExcelImportState state) {
|
905
|
return false;
|
906
|
}
|
907
|
|
908
|
|
909
|
|
910
|
}
|