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.eflora.centralAfrica.ferns;
|
11
|
|
12
|
import java.sql.ResultSet;
|
13
|
import java.sql.SQLException;
|
14
|
import java.util.Arrays;
|
15
|
import java.util.HashMap;
|
16
|
import java.util.HashSet;
|
17
|
import java.util.List;
|
18
|
import java.util.Map;
|
19
|
import java.util.Set;
|
20
|
import java.util.UUID;
|
21
|
|
22
|
import org.apache.commons.lang.StringUtils;
|
23
|
import org.apache.log4j.Logger;
|
24
|
import org.springframework.stereotype.Component;
|
25
|
|
26
|
import eu.etaxonomy.cdm.api.service.IClassificationService;
|
27
|
import eu.etaxonomy.cdm.common.CdmUtils;
|
28
|
import eu.etaxonomy.cdm.io.common.IOValidator;
|
29
|
import eu.etaxonomy.cdm.io.common.TdwgAreaProvider;
|
30
|
import eu.etaxonomy.cdm.io.common.mapping.DbImportMapping;
|
31
|
import eu.etaxonomy.cdm.io.common.mapping.DbImportMethodMapper;
|
32
|
import eu.etaxonomy.cdm.io.common.mapping.DbImportTaxIncludedInMapper;
|
33
|
import eu.etaxonomy.cdm.io.common.mapping.IMappingImport;
|
34
|
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
|
35
|
import eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.validation.CentralAfricaFernsTaxonImportValidator;
|
36
|
import eu.etaxonomy.cdm.model.agent.INomenclaturalAuthor;
|
37
|
import eu.etaxonomy.cdm.model.common.CdmBase;
|
38
|
import eu.etaxonomy.cdm.model.common.Language;
|
39
|
import eu.etaxonomy.cdm.model.common.OriginalSourceType;
|
40
|
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
|
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.TextData;
|
46
|
import eu.etaxonomy.cdm.model.location.Country;
|
47
|
import eu.etaxonomy.cdm.model.location.NamedArea;
|
48
|
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
|
49
|
import eu.etaxonomy.cdm.model.location.NamedAreaType;
|
50
|
import eu.etaxonomy.cdm.model.name.BotanicalName;
|
51
|
import eu.etaxonomy.cdm.model.name.NonViralName;
|
52
|
import eu.etaxonomy.cdm.model.name.Rank;
|
53
|
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
|
54
|
import eu.etaxonomy.cdm.model.reference.Reference;
|
55
|
import eu.etaxonomy.cdm.model.taxon.Classification;
|
56
|
import eu.etaxonomy.cdm.model.taxon.Synonym;
|
57
|
import eu.etaxonomy.cdm.model.taxon.SynonymRelationship;
|
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.model.taxon.TaxonNode;
|
62
|
|
63
|
|
64
|
/**
|
65
|
* @author a.mueller
|
66
|
*/
|
67
|
|
68
|
@Component
|
69
|
public class CentralAfricaFernsTaxonRelationImport extends CentralAfricaFernsImportBase<TaxonBase> implements IMappingImport<TaxonBase, CentralAfricaFernsImportState>{
|
70
|
private static final Logger logger = Logger.getLogger(CentralAfricaFernsTaxonRelationImport.class);
|
71
|
|
72
|
private DbImportMapping<?,?> mapping;
|
73
|
|
74
|
|
75
|
private static final String pluralString = "taxon relations";
|
76
|
private static final String dbTableName = "[African pteridophytes]";
|
77
|
private static final Class<?> cdmTargetClass = TaxonBase.class;
|
78
|
|
79
|
private final Map<String, UUID> nameCacheTaxonMap = new HashMap<String, UUID>();
|
80
|
private final Map<String, UUID> titleCacheTaxonMap = new HashMap<String, UUID>();
|
81
|
|
82
|
private CentralAfricaFernsImportState state;
|
83
|
|
84
|
|
85
|
public CentralAfricaFernsTaxonRelationImport(){
|
86
|
super(pluralString, dbTableName, cdmTargetClass);
|
87
|
}
|
88
|
|
89
|
|
90
|
@Override
|
91
|
protected String getIdQuery() {
|
92
|
String strQuery = " SELECT [Taxon number] FROM " + dbTableName;;
|
93
|
return strQuery;
|
94
|
}
|
95
|
|
96
|
@Override
|
97
|
protected DbImportMapping<?,?> getMapping() {
|
98
|
if (mapping == null){
|
99
|
mapping = new DbImportMapping();
|
100
|
|
101
|
mapping.addMapper(DbImportMethodMapper.NewInstance(this, "createObject", ResultSet.class, CentralAfricaFernsImportState.class));
|
102
|
mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapCommonName", ResultSet.class, CentralAfricaFernsImportState.class));
|
103
|
mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapDistribution", ResultSet.class, CentralAfricaFernsImportState.class ));
|
104
|
mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapEcology", ResultSet.class, CentralAfricaFernsImportState.class));
|
105
|
|
106
|
}
|
107
|
return mapping;
|
108
|
}
|
109
|
|
110
|
/* (non-Javadoc)
|
111
|
* @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getRecordQuery(eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportConfigurator)
|
112
|
*/
|
113
|
@Override
|
114
|
protected String getRecordQuery(CentralAfricaFernsImportConfigurator config) {
|
115
|
String strSelect = " SELECT * ";
|
116
|
String strFrom = " FROM [African pteridophytes] as ap";
|
117
|
String strWhere = " WHERE ( ap.[taxon number] IN (" + ID_LIST_TOKEN + ") )";
|
118
|
String strOrderBy = " ORDER BY [Taxon number]";
|
119
|
String strRecordQuery = strSelect + strFrom + strWhere + strOrderBy ;
|
120
|
return strRecordQuery;
|
121
|
}
|
122
|
|
123
|
|
124
|
/* (non-Javadoc)
|
125
|
* @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#doInvoke(eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportState)
|
126
|
*/
|
127
|
@Override
|
128
|
protected void doInvoke(CentralAfricaFernsImportState state) {
|
129
|
this.state = state;
|
130
|
fillTaxonMap();
|
131
|
super.doInvoke(state);
|
132
|
return;
|
133
|
}
|
134
|
|
135
|
|
136
|
/**
|
137
|
* Fills the nameCache and the titleCache maps. The maps are used to find existing taxa
|
138
|
* by titleCache or nameCache matching.
|
139
|
* Matching may be implemented more sophisticated in future versions.
|
140
|
*/
|
141
|
private void fillTaxonMap() {
|
142
|
List<String> propPath = Arrays.asList(new String []{"name"});
|
143
|
|
144
|
List<Taxon> taxonList = getTaxonService().list(Taxon.class, null, null, null, propPath );
|
145
|
for (Taxon taxon : taxonList){
|
146
|
NonViralName<?> nvn = CdmBase.deproxy(taxon.getName(), NonViralName.class);
|
147
|
UUID uuid = taxon.getUuid();
|
148
|
String nameCache = nvn.getNameCache();
|
149
|
String titleCache = nvn.getTitleCache();
|
150
|
nameCacheTaxonMap.put(nameCache, uuid);
|
151
|
titleCacheTaxonMap.put(titleCache, uuid);
|
152
|
}
|
153
|
}
|
154
|
|
155
|
|
156
|
@Override
|
157
|
public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, CentralAfricaFernsImportState state) {
|
158
|
String nameSpace;
|
159
|
Class<?> cdmClass;
|
160
|
Set<String> idSet;
|
161
|
Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
|
162
|
|
163
|
try{
|
164
|
Set<String> taxonIdSet = new HashSet<String>();
|
165
|
// Set<String> referenceIdSet = new HashSet<String>();
|
166
|
while (rs.next()){
|
167
|
handleForeignKey(rs, taxonIdSet, "Current");
|
168
|
handleForeignKey(rs, taxonIdSet, "Taxon number");
|
169
|
// handleForeignKey(rs, referenceIdSet, "PTRefFk");
|
170
|
}
|
171
|
|
172
|
//taxon map
|
173
|
nameSpace = TAXON_NAMESPACE;
|
174
|
cdmClass = TaxonBase.class;
|
175
|
Map<String, TaxonBase> taxonMap = (Map<String, TaxonBase>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, taxonIdSet, nameSpace);
|
176
|
result.put(nameSpace, taxonMap);
|
177
|
|
178
|
|
179
|
//reference map
|
180
|
this.sourceReference = getFernsSourceReference(state);
|
181
|
// nameSpace = "Reference";
|
182
|
// cdmClass = Reference.class;
|
183
|
// Map<String, Person> referenceMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(Person.class, teamIdSet, nameSpace);
|
184
|
// result.put(Reference.class, referenceMap);
|
185
|
|
186
|
} catch (SQLException e) {
|
187
|
throw new RuntimeException(e);
|
188
|
}
|
189
|
return result;
|
190
|
}
|
191
|
|
192
|
|
193
|
/* (non-Javadoc)
|
194
|
* @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet, eu.etaxonomy.cdm.io.common.ImportStateBase)
|
195
|
*/
|
196
|
@Override
|
197
|
public TaxonBase createObject(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException {
|
198
|
TaxonBase<?> result = null;
|
199
|
try {
|
200
|
String status = rs.getString("Current/Synonym");
|
201
|
String taxonNumber = rs.getString("Taxon number");
|
202
|
state.setTaxonNumber(taxonNumber);
|
203
|
if ("s".equalsIgnoreCase(status)){
|
204
|
//synonym
|
205
|
result = handleSynonym(rs, state);
|
206
|
}else{
|
207
|
//accepted Taxon
|
208
|
result = handleTaxon(rs, state);
|
209
|
}
|
210
|
|
211
|
return result;
|
212
|
} catch (Exception e) {
|
213
|
e.printStackTrace();
|
214
|
return result;
|
215
|
}
|
216
|
|
217
|
}
|
218
|
|
219
|
|
220
|
/**
|
221
|
* Class to store all epithets of the database record. Maybe extended with business logic.
|
222
|
*/
|
223
|
private class Epithets{
|
224
|
private String orderName;
|
225
|
private String subOrderName;
|
226
|
private String familyName;
|
227
|
private String subFamilyName;
|
228
|
private String tribusName;
|
229
|
private String subTribusName;
|
230
|
private String sectionName;
|
231
|
private String subsectionName;
|
232
|
private String genusName;
|
233
|
private String subGenusName;
|
234
|
private String seriesName;
|
235
|
private String specificEpithet;
|
236
|
private String subspeciesName;
|
237
|
private String varietyName;
|
238
|
private String subVariety;
|
239
|
private String formaName;
|
240
|
private String subFormaName;
|
241
|
}
|
242
|
|
243
|
|
244
|
/**
|
245
|
* Handles records with status synonym. A synonym relationship to the accepted taxon
|
246
|
* is created.
|
247
|
* @param rs
|
248
|
* @param state
|
249
|
* @return
|
250
|
* @throws SQLException
|
251
|
*/
|
252
|
private Synonym handleSynonym(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException {
|
253
|
String accTaxonId = rs.getString("Current");
|
254
|
String nomRemarksString = rs.getString("Current/Synonym");
|
255
|
|
256
|
String synonymId = state.getTaxonNumber();
|
257
|
Synonym synonym = (Synonym)state.getRelatedObject(TAXON_NAMESPACE, synonymId);
|
258
|
if (synonym == null){
|
259
|
logger.warn ("Synonym ("+synonymId+")not found.");
|
260
|
return null;
|
261
|
}
|
262
|
TaxonBase<?> taxonBase = CdmBase.deproxy(state.getRelatedObject(TAXON_NAMESPACE, accTaxonId), TaxonBase.class);
|
263
|
|
264
|
if (taxonBase != null){
|
265
|
if (taxonBase.isInstanceOf(Taxon.class)){
|
266
|
Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
|
267
|
SynonymRelationship rel = taxon.addSynonym(synonym, SynonymRelationshipType.SYNONYM_OF());
|
268
|
if ("p.p.".equalsIgnoreCase(nomRemarksString)){
|
269
|
rel.setProParte(true);
|
270
|
}
|
271
|
}else{
|
272
|
logger.warn("Accepted taxon (" + accTaxonId + ") for synonym (" + synonymId +") is not of type 'Current'");
|
273
|
}
|
274
|
}else{
|
275
|
logger.warn("Taxon (" + accTaxonId + ") not found for synonym (" + synonymId +")");
|
276
|
}
|
277
|
|
278
|
return synonym;
|
279
|
}
|
280
|
|
281
|
|
282
|
/**
|
283
|
* Handles all records with status 'current'. Creates parent-child relationships to the
|
284
|
* higher taxa. Uses a complex algorithm to reuse existing higher taxa.
|
285
|
* @param rs
|
286
|
* @param state
|
287
|
* @return
|
288
|
* @throws SQLException
|
289
|
*/
|
290
|
private Taxon handleTaxon(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException {
|
291
|
String taxonNumber = rs.getString("Taxon number");
|
292
|
Taxon child = (Taxon)state.getRelatedObject(TAXON_NAMESPACE, taxonNumber);
|
293
|
if (child == null){
|
294
|
logger.warn("Taxon does not exist: " + taxonNumber);
|
295
|
return null;
|
296
|
}
|
297
|
Epithets epithets = new Epithets();
|
298
|
epithets.orderName = rs.getString("Order name");
|
299
|
epithets.subOrderName = rs.getString("Suborder name");
|
300
|
epithets.familyName = rs.getString("Family name");
|
301
|
epithets.subFamilyName = rs.getString("Subfamily name");
|
302
|
epithets.tribusName = rs.getString("Tribus name");
|
303
|
epithets.subTribusName = rs.getString("Subtribus name");
|
304
|
epithets.sectionName = rs.getString("Section name");
|
305
|
epithets.subsectionName = rs.getString("Subsection name");
|
306
|
epithets.genusName = rs.getString("Genus name");
|
307
|
epithets.subGenusName = rs.getString("Subgenus name");
|
308
|
epithets.seriesName = rs.getString("Series name");
|
309
|
epithets.specificEpithet = rs.getString("Specific epihet");
|
310
|
epithets.subspeciesName = rs.getString("Subspecies name");
|
311
|
epithets.varietyName = rs.getString("Variety name");
|
312
|
epithets.subVariety = rs.getString("Subvariery");
|
313
|
epithets.formaName = rs.getString("Forma name");
|
314
|
epithets.subFormaName = rs.getString("Subforma");
|
315
|
|
316
|
makeNextHigherTaxon(state, rs, child, epithets);
|
317
|
return child;
|
318
|
}
|
319
|
|
320
|
|
321
|
/**
|
322
|
* Adds recursively this taxon to the next higher taxon. If the taxon exists already
|
323
|
* the relationship is not added again.<BR>
|
324
|
* If the author is missing in the old taxon but not in the new taxon the
|
325
|
* old taxon will get the new taxons author.(NOT VALID ANY MORE)<BR>
|
326
|
* If authors differ a new taxon is created.<BR>
|
327
|
* If a higher taxon exists the method is called recursively on this taxon.
|
328
|
* @throws SQLException
|
329
|
*/
|
330
|
private void makeNextHigherTaxon(CentralAfricaFernsImportState state, ResultSet rs, Taxon child, Epithets epithets) throws SQLException {
|
331
|
|
332
|
Taxon constructedHigherTaxon = constructNextHigherTaxon(state, rs, child, epithets);
|
333
|
Reference citation = null;
|
334
|
String microcitation = null;
|
335
|
|
336
|
if (constructedHigherTaxon != null){
|
337
|
handleHigherTaxonMustExist(state, rs, child, epithets, constructedHigherTaxon, citation, microcitation);
|
338
|
}else{
|
339
|
//add taxon to tree if not yet added
|
340
|
if (child.getTaxonNodes().size() == 0){
|
341
|
makeTaxonomicallyIncluded(state, null, child, null, citation, microcitation);
|
342
|
}
|
343
|
}
|
344
|
}
|
345
|
|
346
|
|
347
|
|
348
|
/**
|
349
|
* Handles the case when the database record has data for a taxon of a higher rank
|
350
|
* than the <code>child</code> taxon's rank.
|
351
|
* @param state
|
352
|
* @param rs
|
353
|
* @param child
|
354
|
* @param epithets
|
355
|
* @param higherTaxon
|
356
|
* @param citation
|
357
|
* @param microcitation
|
358
|
* @throws SQLException
|
359
|
*/
|
360
|
private void handleHigherTaxonMustExist(CentralAfricaFernsImportState state, ResultSet rs, Taxon child, Epithets epithets, Taxon constructedHigherTaxon, Reference citation, String microCitation) throws SQLException {
|
361
|
Taxon parentTaxon = getParent(child);
|
362
|
if (parentTaxon == null){
|
363
|
//if no parent taxon exists
|
364
|
Taxon existingTaxon = findExistingNonParentTaxon(state, constructedHigherTaxon);
|
365
|
if (existingTaxon != null){
|
366
|
//a taxon with same title cache or same name cache exists
|
367
|
parentTaxon = mergeExistingAndConstructedTaxon(state, existingTaxon, constructedHigherTaxon);
|
368
|
}else{
|
369
|
parentTaxon = constructedHigherTaxon;
|
370
|
}
|
371
|
makeTaxonomicallyIncluded(state, null, child, parentTaxon, citation, microCitation);
|
372
|
}else{
|
373
|
//parent taxon exists
|
374
|
if (namesMatch(parentTaxon, constructedHigherTaxon)){
|
375
|
//parents match
|
376
|
//TODO what if the higher taxonomy does not match
|
377
|
parentTaxon = mergeExistingAndConstructedTaxon(state, parentTaxon, constructedHigherTaxon);
|
378
|
}else if (compareRanks(parentTaxon, constructedHigherTaxon) != 0){
|
379
|
//ranks unequal
|
380
|
parentTaxon = handleUnequalRanks(parentTaxon, constructedHigherTaxon);
|
381
|
}else if (! nameCachesMatch(parentTaxon, constructedHigherTaxon)){
|
382
|
//nameCache not equal
|
383
|
parentTaxon = handleUnequalNameCaches(parentTaxon, constructedHigherTaxon);
|
384
|
}else if (! authorsMatch(parentTaxon, constructedHigherTaxon)){
|
385
|
//nameCache not equal
|
386
|
parentTaxon = handleUnequalAuthors(parentTaxon, constructedHigherTaxon);
|
387
|
}
|
388
|
}
|
389
|
//save the parent taxon, if it is new
|
390
|
if (parentTaxon == constructedHigherTaxon){
|
391
|
saveConstructedTaxon(state, constructedHigherTaxon);
|
392
|
}
|
393
|
makeNextHigherTaxon(state, rs, parentTaxon, epithets);
|
394
|
}
|
395
|
|
396
|
|
397
|
/**
|
398
|
* Merges author information of the constructed taxon into the existing taxon.
|
399
|
* Returns the existing taxon.
|
400
|
* @param state
|
401
|
* @param parentTaxon
|
402
|
* @param constructedHigherTaxon
|
403
|
*/
|
404
|
private Taxon mergeExistingAndConstructedTaxon(CentralAfricaFernsImportState state, Taxon existingTaxon, Taxon constructedTaxon) {
|
405
|
NonViralName<?> constructedName = CdmBase.deproxy(constructedTaxon.getName(), NonViralName.class);
|
406
|
NonViralName<?> existingName = CdmBase.deproxy(existingTaxon.getName(), NonViralName.class);
|
407
|
if (constructedName.hasAuthors()){
|
408
|
if (! existingName.hasAuthors()){
|
409
|
logger.warn(state.getTaxonNumber() + " - Constrcucted name ("+constructedName.getTitleCache()+") has authors but existing name ("+existingName.getTitleCache()+") has no authors");
|
410
|
}else if (! authorsMatch(constructedName, existingName)){
|
411
|
logger.warn(state.getTaxonNumber() + " - Constrcucted name ("+constructedName.getTitleCache()+") and existing name ("+existingName.getTitleCache()+") have different authors");
|
412
|
}else {
|
413
|
//authors match and are not null
|
414
|
}
|
415
|
}
|
416
|
// more?
|
417
|
return existingTaxon;
|
418
|
}
|
419
|
|
420
|
|
421
|
/**
|
422
|
* Strategy for the decision if an existing parent or a constructed higher taxon should
|
423
|
* be taken as parent in case that the authors of the name differ somehow.
|
424
|
* Current strategy: use existing parent if constructed higher taxon has no authors
|
425
|
* at all. Use constructed taxon otherwise.
|
426
|
* @param existingParentTaxon
|
427
|
* @param constructedHigherTaxon
|
428
|
* @return
|
429
|
*/
|
430
|
private Taxon handleUnequalAuthors(Taxon existingParentTaxon, Taxon constructedHigherTaxon) {
|
431
|
Taxon result;
|
432
|
BotanicalName existingName = CdmBase.deproxy(existingParentTaxon.getName(), BotanicalName.class);
|
433
|
BotanicalName constructedName = (BotanicalName)constructedHigherTaxon.getName();
|
434
|
//current strategy: if constructedName has no authors (and parentName has
|
435
|
if (! constructedName.hasAuthors()){
|
436
|
result = existingParentTaxon;
|
437
|
}else if (! existingName.hasAuthors()){
|
438
|
result = constructedHigherTaxon;
|
439
|
}else{
|
440
|
result = constructedHigherTaxon;
|
441
|
}
|
442
|
return result;
|
443
|
}
|
444
|
|
445
|
/**
|
446
|
* Strategy for the decision if an existing parent or a constructed higher taxon
|
447
|
* should be taken as parent in case that the name caches differ somehow.
|
448
|
* Current strategy: Not implemented. Always use constructed higher taxon.
|
449
|
* @param existingParentTaxon
|
450
|
* @param constructedHigherTaxon
|
451
|
* @return
|
452
|
*/
|
453
|
private Taxon handleUnequalNameCaches(Taxon parentTaxon, Taxon constructedHigherTaxon) {
|
454
|
BotanicalName parentName = CdmBase.deproxy(parentTaxon.getName(), BotanicalName.class);
|
455
|
BotanicalName constructedName = (BotanicalName)constructedHigherTaxon.getName();
|
456
|
logger.warn("handleUnequalNameCaches not yet implemented");
|
457
|
return constructedHigherTaxon;
|
458
|
}
|
459
|
|
460
|
|
461
|
/**
|
462
|
* Handles the case that the existing parent taxon and the constructed parent taxon
|
463
|
* have a diffent rank. Returns the constructedHigherTaxon if no common grand parent exists.
|
464
|
* @param parentTaxon
|
465
|
* @param constructedHigherTaxon
|
466
|
* @return
|
467
|
*/
|
468
|
private Taxon handleUnequalRanks(Taxon parentTaxon, Taxon constructedHigherTaxon) {
|
469
|
BotanicalName parentName = CdmBase.deproxy(parentTaxon.getName(), BotanicalName.class);
|
470
|
BotanicalName constructedName = (BotanicalName)constructedHigherTaxon.getName();
|
471
|
int compare = compareRanks(parentName, constructedName);
|
472
|
Taxon lowerTaxon = parentTaxon;
|
473
|
Taxon grandParentTaxon = constructedHigherTaxon;
|
474
|
if (compare < 0){
|
475
|
lowerTaxon = constructedHigherTaxon;
|
476
|
grandParentTaxon = parentTaxon;
|
477
|
}
|
478
|
Taxon commonGrandParent = checkIsGrandParent(lowerTaxon, grandParentTaxon);
|
479
|
if (commonGrandParent != null){
|
480
|
if (lowerTaxon == constructedHigherTaxon){
|
481
|
//TODO merge
|
482
|
logger.warn("Merge in between taxon not yet implemented");
|
483
|
}
|
484
|
}else{
|
485
|
return constructedHigherTaxon;
|
486
|
}
|
487
|
return lowerTaxon;
|
488
|
}
|
489
|
|
490
|
/**
|
491
|
* Tries to find a taxon which matches the constructed taxon but is not a parent
|
492
|
* taxon of the constructed taxon's child (condition will not be checked).
|
493
|
* Returns null if no such taxon exists.
|
494
|
* @param constructedHigherTaxon
|
495
|
* @param state
|
496
|
* @return
|
497
|
*/
|
498
|
private Taxon findExistingNonParentTaxon(CentralAfricaFernsImportState state, Taxon constructedHigherTaxon) {
|
499
|
BotanicalName constructedName = CdmBase.deproxy(constructedHigherTaxon.getName(), BotanicalName.class);
|
500
|
String titleCache = constructedName.getTitleCache();
|
501
|
String nameCache = constructedName.getNameCache();
|
502
|
UUID existingUuid = titleCacheTaxonMap.get(titleCache);
|
503
|
if (existingUuid == null){
|
504
|
existingUuid = nameCacheTaxonMap.get(nameCache);
|
505
|
}
|
506
|
Taxon relatedTaxon = null;
|
507
|
if (existingUuid != null){
|
508
|
relatedTaxon = state.getRelatedObject(HIGHER_TAXON_NAMESPACE, nameCache, Taxon.class);
|
509
|
if (relatedTaxon == null){
|
510
|
//TODO find for partition
|
511
|
relatedTaxon = (Taxon)getTaxonService().find(existingUuid);
|
512
|
if (relatedTaxon == null){
|
513
|
logger.info(state.getTaxonNumber() + " - Could not find existing name ("+nameCache+") in related objects map");
|
514
|
}else{
|
515
|
state.addRelatedObject(HIGHER_TAXON_NAMESPACE, nameCache, relatedTaxon);
|
516
|
}
|
517
|
}
|
518
|
}
|
519
|
return relatedTaxon;
|
520
|
}
|
521
|
|
522
|
/**
|
523
|
* Checks if a taxon is a grand parent of another taxon
|
524
|
* @param lowerTaxon
|
525
|
* @param higherTaxon
|
526
|
* @return
|
527
|
*/
|
528
|
private Taxon checkIsGrandParent(Taxon childTaxon, Taxon grandParentTaxon) {
|
529
|
BotanicalName lowerName = CdmBase.deproxy(childTaxon.getName(), BotanicalName.class);
|
530
|
BotanicalName higherName = CdmBase.deproxy(grandParentTaxon.getName(), BotanicalName.class);
|
531
|
|
532
|
//TODO was wenn lowerTaxon constructed ist
|
533
|
logger.warn("checkIsGrandParent not yet fully implemented");
|
534
|
Taxon nextParent = getParent(childTaxon);
|
535
|
if (namesMatch(nextParent, grandParentTaxon)){
|
536
|
//TODO which one to return? Merging ?
|
537
|
logger.warn("checkIsGrandParent(matching) not yet fully implemented");
|
538
|
return grandParentTaxon;
|
539
|
}else{
|
540
|
if (compareRanks(lowerName, higherName) >= 0){
|
541
|
return null;
|
542
|
}else{
|
543
|
return checkIsGrandParent(childTaxon, grandParentTaxon);
|
544
|
}
|
545
|
}
|
546
|
}
|
547
|
|
548
|
|
549
|
/**
|
550
|
* Checks if the name caches match.
|
551
|
* @param name1
|
552
|
* @param name2
|
553
|
* @return
|
554
|
*/
|
555
|
private boolean nameCachesMatch(BotanicalName name1, BotanicalName name2) {
|
556
|
return CdmUtils.nullSafeEqual(name1.getNameCache(), name2.getNameCache());
|
557
|
}
|
558
|
|
559
|
/**
|
560
|
* Checks if the name caches of the related names match.
|
561
|
*@param taxon1
|
562
|
* @param taxon2
|
563
|
* @return
|
564
|
*/
|
565
|
private boolean nameCachesMatch(Taxon taxon1, Taxon taxon2) {
|
566
|
BotanicalName name1 = CdmBase.deproxy(taxon1.getName(), BotanicalName.class);
|
567
|
BotanicalName name2 = CdmBase.deproxy(taxon2.getName(), BotanicalName.class);
|
568
|
return nameCachesMatch(name1, name2);
|
569
|
}
|
570
|
|
571
|
|
572
|
/**
|
573
|
* Checks if all authors match
|
574
|
* @param name1
|
575
|
* @param name2
|
576
|
* @return
|
577
|
*/
|
578
|
private boolean authorsMatch(NonViralName<?> name1, NonViralName<?> name2) {
|
579
|
String combinationAuthor1 = name1.computeCombinationAuthorNomenclaturalTitle();
|
580
|
String combinationAuthor2 = name2.computeCombinationAuthorNomenclaturalTitle();
|
581
|
String basionymAuthor1 = name1.computeBasionymAuthorNomenclaturalTitle();
|
582
|
String basionymAuthor2 = name2.computeBasionymAuthorNomenclaturalTitle();
|
583
|
String exCombinationAuthor1 = name1.computeExCombinationAuthorNomenclaturalTitle();
|
584
|
String exCombinationAuthor2 = name2.computeExCombinationAuthorNomenclaturalTitle();
|
585
|
String exBasionymAuthor1 = name1.computeExBasionymAuthorNomenclaturalTitle();
|
586
|
String exBasionymAuthor2 = name2.computeExBasionymAuthorNomenclaturalTitle();
|
587
|
boolean result =
|
588
|
CdmUtils.nullSafeEqual(combinationAuthor1, combinationAuthor2) &&
|
589
|
CdmUtils.nullSafeEqual(basionymAuthor1, basionymAuthor2) &&
|
590
|
CdmUtils.nullSafeEqual(exCombinationAuthor1, exCombinationAuthor2) &&
|
591
|
CdmUtils.nullSafeEqual(exBasionymAuthor1, exBasionymAuthor2);
|
592
|
return result;
|
593
|
}
|
594
|
|
595
|
/**
|
596
|
* Checks if all authors of the related names match.
|
597
|
* @param taxon1
|
598
|
* @param taxon2
|
599
|
* @return
|
600
|
*/
|
601
|
private boolean authorsMatch(Taxon taxon1, Taxon taxon2) {
|
602
|
BotanicalName name1 = CdmBase.deproxy(taxon1.getName(), BotanicalName.class);
|
603
|
BotanicalName name2 = CdmBase.deproxy(taxon2.getName(), BotanicalName.class);
|
604
|
return authorsMatch(name1, name2);
|
605
|
}
|
606
|
|
607
|
/**
|
608
|
* Compares ranks of 2 names.
|
609
|
* @param parentName
|
610
|
* @param constructedName
|
611
|
* @return
|
612
|
*/
|
613
|
private int compareRanks(BotanicalName name1, BotanicalName name2) {
|
614
|
return name1.getRank().compareTo(name2.getRank());
|
615
|
}
|
616
|
|
617
|
/**
|
618
|
* Compares the ranks of the according names.
|
619
|
* @param taxon1
|
620
|
* @param taxon2
|
621
|
* @return
|
622
|
*/
|
623
|
private int compareRanks(Taxon taxon1, Taxon taxon2) {
|
624
|
BotanicalName name1 = CdmBase.deproxy(taxon1.getName(), BotanicalName.class);
|
625
|
BotanicalName name2 = CdmBase.deproxy(taxon2.getName(), BotanicalName.class);
|
626
|
return compareRanks(name1, name2);
|
627
|
}
|
628
|
|
629
|
|
630
|
|
631
|
/**
|
632
|
* Checks if 2 names match.
|
633
|
* Current strategy: true, if ranks are equal, nameCaches match and authors match
|
634
|
* @param name1
|
635
|
* @param name2
|
636
|
* @return
|
637
|
*/
|
638
|
private boolean namesMatch(BotanicalName name1, BotanicalName name2) {
|
639
|
return compareRanks(name1, name2)==0 && nameCachesMatch(name1, name2) && authorsMatch(name1, name2);
|
640
|
}
|
641
|
|
642
|
/**
|
643
|
* Checks if the according names match.
|
644
|
* @see #namesMatch(BotanicalName, BotanicalName)
|
645
|
* @param taxon1
|
646
|
* @param taxon2
|
647
|
* @return
|
648
|
*/
|
649
|
private boolean namesMatch(Taxon taxon1, Taxon taxon2) {
|
650
|
BotanicalName name1 = CdmBase.deproxy(taxon1.getName(), BotanicalName.class);
|
651
|
BotanicalName name2 = CdmBase.deproxy(taxon2.getName(), BotanicalName.class);
|
652
|
return namesMatch(name1, name2);
|
653
|
}
|
654
|
|
655
|
|
656
|
/**
|
657
|
* Returns the only parent of the taxon. If not parent exists <code>null</code> is
|
658
|
* returned.
|
659
|
* TODO move to taxon class (with classification)
|
660
|
* @param child
|
661
|
* @return
|
662
|
* @throws IllegalStateException if taxon belongs to multiple states
|
663
|
*/
|
664
|
private Taxon getParent(Taxon child) {
|
665
|
int countNodes = child.getTaxonNodes().size();
|
666
|
if (countNodes < 1){
|
667
|
return null;
|
668
|
}else if (countNodes > 1){
|
669
|
throw new IllegalStateException("Multiple nodes exist for child taxon. This is an invalid state for this import.");
|
670
|
}else{
|
671
|
TaxonNode childNode = child.getTaxonNodes().iterator().next();
|
672
|
TaxonNode parentNode = childNode.getParent();
|
673
|
if (parentNode != null){
|
674
|
return parentNode.getTaxon();
|
675
|
}else{
|
676
|
return null;
|
677
|
}
|
678
|
}
|
679
|
}
|
680
|
|
681
|
|
682
|
/**
|
683
|
* Persists and saves the newly created taxon to the CDM store and to the look-up
|
684
|
* maps.
|
685
|
* @param state
|
686
|
* @param constructedHigherTaxon
|
687
|
* @return
|
688
|
*/
|
689
|
private Taxon saveConstructedTaxon(CentralAfricaFernsImportState state, Taxon constructedHigherTaxon) {
|
690
|
BotanicalName constructedName = CdmBase.deproxy(constructedHigherTaxon.getName(), BotanicalName.class);
|
691
|
String nameCache = constructedName.getNameCache();
|
692
|
String titleCache = constructedName.getTitleCache();
|
693
|
nameCacheTaxonMap.put(nameCache, constructedHigherTaxon.getUuid());
|
694
|
titleCacheTaxonMap.put(titleCache, constructedHigherTaxon.getUuid());
|
695
|
state.addRelatedObject(HIGHER_TAXON_NAMESPACE, nameCache, constructedHigherTaxon);
|
696
|
|
697
|
//persist
|
698
|
// Reference citation = state.getConfig().getSourceReference(); //throws nonUniqueObject exception
|
699
|
Reference citation = null;
|
700
|
String id = state.getTaxonNumber() + "-" + constructedName.getRank().getTitleCache();
|
701
|
addOriginalSource(constructedName, id, NAME_NAMESPACE, citation);
|
702
|
addOriginalSource(constructedHigherTaxon, id, TAXON_NAMESPACE, citation);
|
703
|
getTaxonService().save(constructedHigherTaxon);
|
704
|
|
705
|
return constructedHigherTaxon;
|
706
|
}
|
707
|
|
708
|
|
709
|
//TODO use Mapper
|
710
|
/**
|
711
|
* Adds the parent child relationship. Creates and saves the classification if needed.
|
712
|
* Adds parent and child to the classification.
|
713
|
* @param state
|
714
|
* @param treeRefFk
|
715
|
* @param child
|
716
|
* @param parent
|
717
|
* @param citation
|
718
|
* @param microCitation
|
719
|
* @return
|
720
|
*/
|
721
|
private boolean makeTaxonomicallyIncluded(CentralAfricaFernsImportState state, Integer treeRefFk, Taxon child, Taxon parent, Reference citation, String microCitation){
|
722
|
String treeKey;
|
723
|
UUID treeUuid;
|
724
|
if (treeRefFk == null){
|
725
|
treeKey = "1"; // there is only one tree and it gets the map key '1'
|
726
|
treeUuid = state.getConfig().getClassificationUuid();
|
727
|
}else{
|
728
|
treeKey =String.valueOf(treeRefFk);
|
729
|
treeUuid = state.getTreeUuidByTreeKey(treeKey);
|
730
|
}
|
731
|
Classification tree = (Classification)state.getRelatedObject(DbImportTaxIncludedInMapper.TAXONOMIC_TREE_NAMESPACE, treeKey);
|
732
|
if (tree == null){
|
733
|
IClassificationService service = state.getCurrentIO().getClassificationService();
|
734
|
tree = service.find(treeUuid);
|
735
|
if (tree == null){
|
736
|
String treeName = state.getConfig().getClassificationName();
|
737
|
tree = Classification.NewInstance(treeName);
|
738
|
tree.setUuid(treeUuid);
|
739
|
//FIXME tree reference
|
740
|
tree.setReference(citation);
|
741
|
service.save(tree);
|
742
|
}
|
743
|
state.addRelatedObject(DbImportTaxIncludedInMapper.TAXONOMIC_TREE_NAMESPACE, treeKey, tree);
|
744
|
}
|
745
|
|
746
|
TaxonNode childNode;
|
747
|
if (parent != null){
|
748
|
childNode = tree.addParentChild(parent, child, citation, microCitation);
|
749
|
}else{
|
750
|
childNode = tree.addChildTaxon(child, citation, microCitation);
|
751
|
}
|
752
|
return (childNode != null);
|
753
|
}
|
754
|
|
755
|
|
756
|
/**
|
757
|
* Reasons if a higher taxon should exist. If it should exist it returns it as a new taxon.
|
758
|
* Returns null otherwise.
|
759
|
* @return
|
760
|
* @throws SQLException
|
761
|
*/
|
762
|
private Taxon constructNextHigherTaxon(CentralAfricaFernsImportState state, ResultSet rs, Taxon childTaxon, Epithets epithets) throws SQLException {
|
763
|
|
764
|
Taxon result = null;
|
765
|
BotanicalName childName = CdmBase.deproxy(childTaxon.getName(), BotanicalName.class);
|
766
|
Rank childRank = childName.getRank();
|
767
|
BotanicalName higherName;
|
768
|
higherName = handleInfraSpecific(childRank, epithets);
|
769
|
if (higherName.getRank() == null){
|
770
|
handleSpecies(childRank, higherName, epithets);
|
771
|
}
|
772
|
if (higherName.getRank() == null){
|
773
|
handleInfraGeneric(childRank, higherName, epithets);
|
774
|
}
|
775
|
if (higherName.getRank() == null){
|
776
|
handleUninomial(childRank, higherName, epithets);
|
777
|
}
|
778
|
|
779
|
if (higherName.getRank() != null){
|
780
|
result = Taxon.NewInstance(higherName, childTaxon.getSec());
|
781
|
//TODO correct??
|
782
|
setAuthor(higherName, rs, state.getTaxonNumber(), true);
|
783
|
// UUID uuid = higherName.getUuid();
|
784
|
// String name = higherName.getNameCache();
|
785
|
// taxonMap.put(name, uuid);
|
786
|
// state.addRelatedObject(HIGHER_TAXON_NAMESPACE, higherName.getNameCache(), result);
|
787
|
}
|
788
|
return result;
|
789
|
}
|
790
|
|
791
|
private BotanicalName handleInfraSpecific(Rank lowerTaxonRank, Epithets epithets) {
|
792
|
|
793
|
BotanicalName taxonName = BotanicalName.NewInstance(null);
|
794
|
Rank newRank = null;
|
795
|
|
796
|
if (StringUtils.isNotBlank(epithets.subFormaName) && lowerTaxonRank.isLower(Rank.SUBFORM())){
|
797
|
taxonName.setInfraSpecificEpithet(epithets.subFormaName);
|
798
|
newRank = Rank.SUBFORM();
|
799
|
}else if (StringUtils.isNotBlank(epithets.formaName) && lowerTaxonRank.isLower(Rank.FORM())){
|
800
|
taxonName.setInfraSpecificEpithet(epithets.formaName);
|
801
|
newRank = Rank.FORM();
|
802
|
}else if (StringUtils.isNotBlank(epithets.subVariety) && lowerTaxonRank.isLower(Rank.SUBVARIETY())){
|
803
|
taxonName.setInfraSpecificEpithet(epithets.subVariety);
|
804
|
newRank = Rank.SUBVARIETY();
|
805
|
}else if (StringUtils.isNotBlank(epithets.varietyName) && lowerTaxonRank.isLower(Rank.VARIETY())){
|
806
|
taxonName.setInfraSpecificEpithet(epithets.varietyName);
|
807
|
newRank = Rank.VARIETY();
|
808
|
}else if (StringUtils.isNotBlank(epithets.subspeciesName) && lowerTaxonRank.isLower(Rank.SUBSPECIES())){
|
809
|
taxonName.setInfraSpecificEpithet(epithets.subspeciesName);
|
810
|
newRank = Rank.SUBSPECIES();
|
811
|
}
|
812
|
|
813
|
if (newRank != null){
|
814
|
taxonName.setSpecificEpithet(epithets.specificEpithet);
|
815
|
taxonName.setGenusOrUninomial(epithets.genusName);
|
816
|
taxonName.setRank(newRank);
|
817
|
}
|
818
|
|
819
|
return taxonName;
|
820
|
}
|
821
|
|
822
|
private BotanicalName handleSpecies(Rank lowerTaxonRank, BotanicalName taxonName, Epithets epithets) {
|
823
|
Rank newRank = null;
|
824
|
|
825
|
if (StringUtils.isNotBlank(epithets.specificEpithet) && lowerTaxonRank.isLower(Rank.SPECIES())){
|
826
|
taxonName.setSpecificEpithet(epithets.specificEpithet);
|
827
|
newRank = Rank.SPECIES();
|
828
|
}
|
829
|
if (newRank != null){
|
830
|
taxonName.setGenusOrUninomial(epithets.genusName);
|
831
|
taxonName.setRank(newRank);
|
832
|
}
|
833
|
return taxonName;
|
834
|
}
|
835
|
|
836
|
private BotanicalName handleInfraGeneric(Rank lowerTaxonRank, BotanicalName taxonName, Epithets epithets) {
|
837
|
Rank newRank = null;
|
838
|
|
839
|
if (StringUtils.isNotBlank(epithets.seriesName) && lowerTaxonRank.isLower(Rank.SERIES())){
|
840
|
taxonName.setInfraGenericEpithet(epithets.seriesName);
|
841
|
newRank = Rank.SERIES();
|
842
|
}else if (StringUtils.isNotBlank(epithets.subsectionName) && lowerTaxonRank.isLower(Rank.SUBSECTION_BOTANY())){
|
843
|
taxonName.setInfraGenericEpithet(epithets.subsectionName);
|
844
|
newRank = Rank.SUBSECTION_BOTANY();
|
845
|
}else if (StringUtils.isNotBlank(epithets.sectionName) && lowerTaxonRank.isLower(Rank.SECTION_BOTANY())){
|
846
|
taxonName.setInfraGenericEpithet(epithets.sectionName);
|
847
|
newRank = Rank.SECTION_BOTANY();
|
848
|
}else if (StringUtils.isNotBlank(epithets.subGenusName) && lowerTaxonRank.isLower(Rank.SUBGENUS())){
|
849
|
taxonName.setInfraGenericEpithet(epithets.subGenusName);
|
850
|
newRank = Rank.SUBGENUS();
|
851
|
}
|
852
|
if (newRank != null){
|
853
|
taxonName.setGenusOrUninomial(epithets.genusName);
|
854
|
taxonName.setRank(newRank);
|
855
|
}
|
856
|
return taxonName;
|
857
|
}
|
858
|
|
859
|
|
860
|
|
861
|
private BotanicalName handleUninomial(Rank lowerTaxonRank, BotanicalName taxonName, Epithets epithets) {
|
862
|
|
863
|
Rank newRank = null;
|
864
|
if (StringUtils.isNotBlank(epithets.genusName) && lowerTaxonRank.isLower(Rank.GENUS())){
|
865
|
taxonName.setGenusOrUninomial(epithets.genusName);
|
866
|
newRank = Rank.GENUS();
|
867
|
}else if (StringUtils.isNotBlank(epithets.subTribusName) && lowerTaxonRank.isLower(Rank.SUBTRIBE())){
|
868
|
taxonName.setGenusOrUninomial(epithets.subTribusName);
|
869
|
newRank = Rank.SUBTRIBE();
|
870
|
}else if (StringUtils.isNotBlank(epithets.tribusName) && lowerTaxonRank.isLower(Rank.TRIBE())){
|
871
|
taxonName.setGenusOrUninomial(epithets.tribusName);
|
872
|
newRank = Rank.TRIBE();
|
873
|
}else if (StringUtils.isNotBlank(epithets.subFamilyName) && lowerTaxonRank.isLower(Rank.SUBFAMILY())){
|
874
|
taxonName.setGenusOrUninomial(epithets.subFamilyName);
|
875
|
newRank = Rank.SUBFAMILY();
|
876
|
}else if (StringUtils.isNotBlank(epithets.familyName) && lowerTaxonRank.isLower(Rank.FAMILY())){
|
877
|
taxonName.setGenusOrUninomial(epithets.familyName);
|
878
|
newRank = Rank.FAMILY();
|
879
|
}else if (StringUtils.isNotBlank(epithets.subOrderName) && lowerTaxonRank.isLower(Rank.SUBORDER())){
|
880
|
taxonName.setGenusOrUninomial(epithets.subOrderName);
|
881
|
newRank = Rank.SUBORDER();
|
882
|
}else if (StringUtils.isNotBlank(epithets.orderName) && lowerTaxonRank.isLower(Rank.ORDER())){
|
883
|
taxonName.setGenusOrUninomial(epithets.orderName);
|
884
|
newRank = Rank.ORDER();
|
885
|
}
|
886
|
taxonName.setRank(newRank);
|
887
|
return taxonName;
|
888
|
}
|
889
|
|
890
|
|
891
|
/**
|
892
|
* for internal use only, used by MethodMapper
|
893
|
*/
|
894
|
private TaxonBase mapCommonName(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
|
895
|
String taxonNumber = state.getTaxonNumber();
|
896
|
String commonNames = rs.getString("Common names");
|
897
|
TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
|
898
|
if (StringUtils.isNotBlank(commonNames)){
|
899
|
Taxon taxon = getAcceptedTaxon(taxonBase);
|
900
|
if ( taxon != null ){
|
901
|
TaxonDescription description = getTaxonDescription(taxon, false, true);
|
902
|
String[] split = commonNames.split(",");
|
903
|
for (String commonNameString: split){
|
904
|
CommonTaxonName commonName = CommonTaxonName.NewInstance(commonNameString.trim(), Language.ENGLISH());
|
905
|
description.addElement(commonName);
|
906
|
}
|
907
|
}else{
|
908
|
logger.warn(taxonNumber + " - Accepted taxon for synonym can't be defined for common name. Synonym " + taxonBase.getName().getTitleCache());
|
909
|
}
|
910
|
}
|
911
|
return taxonBase;
|
912
|
}
|
913
|
|
914
|
|
915
|
/**
|
916
|
* for internal use only, used by MethodMapper
|
917
|
*/
|
918
|
private TaxonBase mapDistribution(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
|
919
|
try {
|
920
|
String taxonNumber = state.getTaxonNumber();
|
921
|
// logger.info(taxonNumber);
|
922
|
TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
|
923
|
String countriesString = rs.getString("Distribution - Country");
|
924
|
String province = rs.getString("Distribution - Province");
|
925
|
String distributionDetailed = rs.getString("Distribution - detailed");
|
926
|
if (taxonBase != null){
|
927
|
TaxonNameBase<?,?> nameUsedInSource = taxonBase.getName();
|
928
|
Taxon taxon = getAcceptedTaxon(taxonBase);
|
929
|
if (taxon != null){
|
930
|
|
931
|
if (StringUtils.isNotBlank(countriesString) ){
|
932
|
makeCountries(state, taxonNumber, taxon, nameUsedInSource, countriesString, province, distributionDetailed);
|
933
|
}
|
934
|
makeProvince(taxon, province);
|
935
|
makeDistributionDetailed(taxon, distributionDetailed);
|
936
|
}else{
|
937
|
logger.warn(taxonNumber + " - Accepted taxon for synonym can't be defined for distribution. Synonym " + taxonBase.getName().getTitleCache());
|
938
|
}
|
939
|
}else{
|
940
|
logger.warn(" - " + taxonNumber + ": TaxonBase was null");
|
941
|
}
|
942
|
return taxonBase;
|
943
|
} catch (Exception e) {
|
944
|
e.printStackTrace();
|
945
|
return null;
|
946
|
}
|
947
|
}
|
948
|
|
949
|
|
950
|
/**
|
951
|
* for internal use only, used by MethodMapper
|
952
|
* @param commonNames
|
953
|
*/
|
954
|
private TaxonBase mapEcology(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
|
955
|
String taxonNumber = state.getTaxonNumber();
|
956
|
String ecologyString = rs.getString("Ecology");
|
957
|
TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
|
958
|
if (StringUtils.isNotBlank(ecologyString)){
|
959
|
Taxon taxon = getAcceptedTaxon(taxonBase);
|
960
|
|
961
|
if (taxon != null){
|
962
|
TaxonDescription description = getTaxonDescription(taxon, false, true);
|
963
|
TextData ecology = TextData.NewInstance(Feature.ECOLOGY());
|
964
|
ecology.putText(Language.ENGLISH(), ecologyString.trim());
|
965
|
description.addElement(ecology);
|
966
|
}else{
|
967
|
logger.warn(taxonNumber + " - Accepted taxon for synonym can't be defined for ecology. Synonym " + taxonBase.getName().getTitleCache());
|
968
|
}
|
969
|
}
|
970
|
return taxonBase;
|
971
|
}
|
972
|
|
973
|
|
974
|
|
975
|
|
976
|
private void makeDistributionDetailed(Taxon taxon, String distributionDetailed) {
|
977
|
if (StringUtils.isNotBlank(distributionDetailed)){
|
978
|
TaxonDescription description = getTaxonDescription(taxon, false, true);
|
979
|
TextData distribution = TextData.NewInstance(Feature.DISTRIBUTION());
|
980
|
description.addElement(distribution);
|
981
|
distribution.putText(Language.ENGLISH(), distributionDetailed);
|
982
|
}
|
983
|
}
|
984
|
|
985
|
|
986
|
private void makeProvince(Taxon taxon, String province) {
|
987
|
if (StringUtils.isNotBlank(province)){
|
988
|
TaxonDescription description = getTaxonDescription(taxon, false, true);
|
989
|
TextData distribution = TextData.NewInstance(Feature.DISTRIBUTION());
|
990
|
description.addElement(distribution);
|
991
|
distribution.putText(Language.ENGLISH(), province);
|
992
|
}
|
993
|
}
|
994
|
|
995
|
|
996
|
/**
|
997
|
* @param state
|
998
|
* @param taxonNumber
|
999
|
* @param taxonBase
|
1000
|
* @param countriesString
|
1001
|
*/
|
1002
|
private void makeCountries(CentralAfricaFernsImportState state, String taxonNumber, Taxon taxon, TaxonNameBase nameUsedInSource, String countriesString, String province, String distributionDetailed) {
|
1003
|
countriesString = countriesString.replaceAll("\\*", "");
|
1004
|
countriesString = countriesString.replace(" ", " ");
|
1005
|
countriesString = countriesString.replace(", endemic", " - endemic");
|
1006
|
countriesString = countriesString.replace("(endemic)", " - endemic");
|
1007
|
countriesString = countriesString.replace("(introduced)", " - introduced");
|
1008
|
countriesString = countriesString.replace("(naturalised)", " - naturalised");
|
1009
|
countriesString = countriesString.replace("Madagascar-", "Madagascar -");
|
1010
|
countriesString = countriesString.replace("Mah\u00e9", "Mahe");
|
1011
|
|
1012
|
String[] split = countriesString.split("[,;]");
|
1013
|
String remainingString = null;
|
1014
|
for (String countryString : split){
|
1015
|
countryString = CdmUtils.concat(", ", remainingString , countryString);
|
1016
|
if (countryString.matches(".*\\(.*") && ! countryString.matches(".*\\).*")){
|
1017
|
remainingString = countryString;
|
1018
|
continue;
|
1019
|
}
|
1020
|
remainingString = null;
|
1021
|
try {
|
1022
|
makeSingleCountry(state, taxonNumber, taxon, nameUsedInSource, countryString.trim());
|
1023
|
} catch (UndefinedTransformerMethodException e) {
|
1024
|
e.printStackTrace();
|
1025
|
}
|
1026
|
}
|
1027
|
}
|
1028
|
|
1029
|
|
1030
|
private void makeSingleCountry(CentralAfricaFernsImportState state, String taxonNumber, Taxon taxon, TaxonNameBase nameUsedInSource, String country) throws UndefinedTransformerMethodException {
|
1031
|
boolean areaDoubtful = false;
|
1032
|
Distribution distribution = Distribution.NewInstance(null, PresenceAbsenceTerm.PRESENT());
|
1033
|
Reference sourceReference = this.sourceReference;
|
1034
|
distribution.addSource(OriginalSourceType.Import, taxonNumber, "Distribution_Country", sourceReference, null, nameUsedInSource, null);
|
1035
|
NamedArea area = null;
|
1036
|
//empty
|
1037
|
if (StringUtils.isBlank(country)){
|
1038
|
return;
|
1039
|
}
|
1040
|
country = country.trim();
|
1041
|
//doubtful
|
1042
|
if (country.startsWith("?")){
|
1043
|
areaDoubtful = true;
|
1044
|
country = country.substring(1).trim();
|
1045
|
}
|
1046
|
//status
|
1047
|
country = makeCountryStatus(state, country, distribution);
|
1048
|
|
1049
|
//brackets
|
1050
|
country = makeCountryBrackets(state, taxonNumber, taxon, nameUsedInSource, country);
|
1051
|
String countryWithoutIslands = null;
|
1052
|
String countryWithoutDot = null;
|
1053
|
if (country.endsWith(" Isl.") || country.endsWith(" isl.") ){
|
1054
|
countryWithoutIslands = country.substring(0, country.length()-5);
|
1055
|
}
|
1056
|
if (country.endsWith(".")){
|
1057
|
countryWithoutDot = country.substring(0, country.length()-1);
|
1058
|
}
|
1059
|
if (country.endsWith("*")){
|
1060
|
country = country.substring(0, country.length()-1);
|
1061
|
}
|
1062
|
if (country.endsWith("Islands")){
|
1063
|
country = country.replace("Islands", "Is.");
|
1064
|
}
|
1065
|
|
1066
|
|
1067
|
//areas
|
1068
|
if (TdwgAreaProvider.isTdwgAreaLabel(country)){
|
1069
|
//tdwg
|
1070
|
area = TdwgAreaProvider.getAreaByTdwgLabel(country);
|
1071
|
}else if (TdwgAreaProvider.isTdwgAreaLabel(countryWithoutIslands)){
|
1072
|
//tdwg
|
1073
|
area = TdwgAreaProvider.getAreaByTdwgLabel(countryWithoutIslands);
|
1074
|
}else if (TdwgAreaProvider.isTdwgAreaLabel(countryWithoutDot)){
|
1075
|
//tdwg
|
1076
|
area = TdwgAreaProvider.getAreaByTdwgLabel(countryWithoutDot);
|
1077
|
}else if ( (area = state.getTransformer().getNamedAreaByKey(country)) != null) {
|
1078
|
//area already set
|
1079
|
}else if (Country.isCountryLabel(country)){
|
1080
|
//iso
|
1081
|
area = Country.getCountryByLabel(country);
|
1082
|
}else{
|
1083
|
//others
|
1084
|
NamedAreaLevel level = null;
|
1085
|
NamedAreaType areaType = null;
|
1086
|
|
1087
|
UUID uuid = state.getTransformer().getNamedAreaUuid(country);
|
1088
|
if (uuid == null){
|
1089
|
logger.error(taxonNumber + " - Unknown country: " + country);
|
1090
|
}
|
1091
|
area = getNamedArea(state, uuid, country, country, country, areaType, level);
|
1092
|
}
|
1093
|
|
1094
|
distribution.setArea(area);
|
1095
|
if (areaDoubtful == true){
|
1096
|
if (distribution.getStatus().equals(PresenceAbsenceTerm.PRESENT())){
|
1097
|
distribution.setStatus(PresenceAbsenceTerm.PRESENT_DOUBTFULLY());
|
1098
|
}
|
1099
|
}
|
1100
|
TaxonDescription description = getTaxonDescription(taxon, false, true);
|
1101
|
description.addElement(distribution);
|
1102
|
}
|
1103
|
|
1104
|
|
1105
|
|
1106
|
/**
|
1107
|
* @param state
|
1108
|
* @return
|
1109
|
*/
|
1110
|
private Reference sourceReference = null;
|
1111
|
private Reference getFernsSourceReference(CentralAfricaFernsImportState state) {
|
1112
|
// if (sourceReference == null || true){
|
1113
|
Reference tmpReference = state.getConfig().getSourceReference();
|
1114
|
sourceReference = getReferenceService().find(tmpReference.getUuid());
|
1115
|
// }
|
1116
|
return sourceReference;
|
1117
|
}
|
1118
|
|
1119
|
|
1120
|
private String makeCountryBrackets(CentralAfricaFernsImportState state, String taxonNumber, Taxon taxon, TaxonNameBase<?,?> nameUsedInSource, String country) {
|
1121
|
String[] split = (country + " ").split("\\(.*\\)");
|
1122
|
if (split.length == 2){
|
1123
|
String bracket = country.substring(split[0].length()+1, country.indexOf(")"));
|
1124
|
country = split[0].trim();
|
1125
|
makeCountries(state, taxonNumber, taxon, nameUsedInSource, bracket, null, null);
|
1126
|
}else if (split.length ==1){
|
1127
|
//do nothing
|
1128
|
}else{
|
1129
|
logger.warn("Illegal length");
|
1130
|
}
|
1131
|
return country;
|
1132
|
}
|
1133
|
|
1134
|
private String makeCountryStatus(CentralAfricaFernsImportState state, String country, Distribution distribution) throws UndefinedTransformerMethodException {
|
1135
|
PresenceAbsenceTerm status = null;
|
1136
|
String[] split = country.split(" - ");
|
1137
|
|
1138
|
if (split.length == 2){
|
1139
|
country = split[0].trim();
|
1140
|
String statusString = split[1];
|
1141
|
statusString = statusString.replace(".", "");
|
1142
|
status = state.getTransformer().getPresenceTermByKey(statusString);
|
1143
|
if (status == null){
|
1144
|
logger.warn("No status found: "+ statusString);
|
1145
|
}
|
1146
|
// UUID uuid = null;
|
1147
|
// status = getPresenceTerm(state, uuid, statusString, statusString, null);
|
1148
|
}else if (split.length == 1){
|
1149
|
//nothing to do
|
1150
|
}else{
|
1151
|
logger.warn("Invalid length: " + split.length);
|
1152
|
}
|
1153
|
if (status != null){
|
1154
|
distribution.setStatus(status);
|
1155
|
}
|
1156
|
return country;
|
1157
|
}
|
1158
|
|
1159
|
|
1160
|
|
1161
|
|
1162
|
/* (non-Javadoc)
|
1163
|
* @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
|
1164
|
*/
|
1165
|
@Override
|
1166
|
protected boolean doCheck(CentralAfricaFernsImportState state){
|
1167
|
IOValidator<CentralAfricaFernsImportState> validator = new CentralAfricaFernsTaxonImportValidator();
|
1168
|
return validator.validate(state);
|
1169
|
}
|
1170
|
|
1171
|
/* (non-Javadoc)
|
1172
|
* @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
|
1173
|
*/
|
1174
|
@Override
|
1175
|
protected boolean isIgnore(CentralAfricaFernsImportState state){
|
1176
|
return ! state.getConfig().isDoRelTaxa();
|
1177
|
}
|
1178
|
|
1179
|
|
1180
|
|
1181
|
//************************ OLD **********************************************************
|
1182
|
|
1183
|
/**
|
1184
|
* Adds the higherTaxon authors to the existingHigherTaxon authors if the higherTaxon has authors and
|
1185
|
* the existingHigherTaxon has no authors.
|
1186
|
* Returns false if both taxa have authors and the authors differ from each other.
|
1187
|
* @param higherTaxon
|
1188
|
* @param existingHigherTaxon
|
1189
|
*/
|
1190
|
private boolean mergeAuthors_old(Taxon higherTaxon, Taxon existingHigherTaxon) {
|
1191
|
NonViralName<?> existingName = CdmBase.deproxy(higherTaxon.getName(), NonViralName.class);
|
1192
|
NonViralName<?> newName = CdmBase.deproxy(existingHigherTaxon.getName(), NonViralName.class);
|
1193
|
if (existingName == newName){
|
1194
|
return true;
|
1195
|
}
|
1196
|
if (! newName.hasAuthors()){
|
1197
|
return true;
|
1198
|
}
|
1199
|
if (! existingName.hasAuthors()){
|
1200
|
existingName.setCombinationAuthorship(newName.getCombinationAuthorship());
|
1201
|
existingName.setExCombinationAuthorship(newName.getExCombinationAuthorship());
|
1202
|
existingName.setBasionymAuthorship(newName.getBasionymAuthorship());
|
1203
|
existingName.setExBasionymAuthorship(newName.getExBasionymAuthorship());
|
1204
|
return true;
|
1205
|
}
|
1206
|
boolean authorsAreSame = true;
|
1207
|
authorsAreSame &= getNomTitleNz(existingName.getCombinationAuthorship()).equals(getNomTitleNz(newName.getCombinationAuthorship()));
|
1208
|
authorsAreSame &= getNomTitleNz(existingName.getExCombinationAuthorship()).equals(getNomTitleNz(newName.getExCombinationAuthorship()));
|
1209
|
authorsAreSame &= getNomTitleNz(existingName.getBasionymAuthorship()).equals(getNomTitleNz(newName.getBasionymAuthorship()));
|
1210
|
authorsAreSame &= getNomTitleNz(existingName.getExBasionymAuthorship()).equals(getNomTitleNz(newName.getExBasionymAuthorship()));
|
1211
|
return authorsAreSame;
|
1212
|
|
1213
|
|
1214
|
}
|
1215
|
|
1216
|
/**
|
1217
|
* Returns the nomenclatural title of the author. Returns empty string if author is <code>null</code> or
|
1218
|
* titleCache is <code>null</code>.
|
1219
|
* @param author
|
1220
|
* @return
|
1221
|
*/
|
1222
|
private String getNomTitleNz(INomenclaturalAuthor author) {
|
1223
|
if (author != null){
|
1224
|
return CdmUtils.Nz(author.getNomenclaturalTitle());
|
1225
|
}else{
|
1226
|
return "";
|
1227
|
}
|
1228
|
}
|
1229
|
|
1230
|
private Taxon getExistingHigherTaxon_old(Taxon child, Taxon higherTaxon) {
|
1231
|
int countNodes = child.getTaxonNodes().size();
|
1232
|
if (countNodes < 1){
|
1233
|
return null;
|
1234
|
}else if (countNodes > 1){
|
1235
|
throw new IllegalStateException("Multiple nodes exist for child taxon. This is an invalid state.");
|
1236
|
}else{
|
1237
|
TaxonNode childNode = child.getTaxonNodes().iterator().next();
|
1238
|
TaxonNode parentNode = childNode.getParent();
|
1239
|
if (parentNode != null){
|
1240
|
String existingParentTitle = parentNode.getTaxon().getName().getTitleCache();
|
1241
|
String newParentTitle = higherTaxon.getName().getTitleCache();
|
1242
|
if (existingParentTitle.equals(newParentTitle)){
|
1243
|
return parentNode.getTaxon();
|
1244
|
}
|
1245
|
}
|
1246
|
return null;
|
1247
|
}
|
1248
|
}
|
1249
|
|
1250
|
|
1251
|
|
1252
|
/**
|
1253
|
* Tests if this the child taxon already is a child of the higher taxon.
|
1254
|
* @param child
|
1255
|
* @param higherTaxon
|
1256
|
* @return
|
1257
|
*/
|
1258
|
private boolean includedRelationshipExists_Old(Taxon child, Taxon higherTaxon) {
|
1259
|
int countNodes = higherTaxon.getTaxonNodes().size();
|
1260
|
if (countNodes < 1){
|
1261
|
return false;
|
1262
|
}else if (countNodes > 1){
|
1263
|
throw new IllegalStateException("Multiple nodes exist for higher taxon. This is an invalid state.");
|
1264
|
}else{
|
1265
|
TaxonNode higherNode = higherTaxon.getTaxonNodes().iterator().next();
|
1266
|
return childExists_old(child, higherNode);
|
1267
|
}
|
1268
|
}
|
1269
|
|
1270
|
|
1271
|
|
1272
|
private boolean childExists_old(Taxon child, TaxonNode higherNode) {
|
1273
|
for (TaxonNode childNode : higherNode.getChildNodes()){
|
1274
|
String existingChildTitle = childNode.getTaxon().getName().getTitleCache();
|
1275
|
String newChildTitle = child.getName().getTitleCache();
|
1276
|
if (existingChildTitle.equals(newChildTitle)){
|
1277
|
return true;
|
1278
|
}
|
1279
|
}
|
1280
|
return false;
|
1281
|
}
|
1282
|
|
1283
|
|
1284
|
}
|