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