Project

General

Profile

Download (13.9 KB) Statistics
| Branch: | Revision:
1
/**
2
 * Copyright (C) 2007 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9

    
10
package eu.etaxonomy.cdm.io.phycobank;
11

    
12
import java.util.ArrayList;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.Set;
16
import java.util.UUID;
17

    
18
import org.apache.log4j.Logger;
19
import org.springframework.stereotype.Component;
20

    
21
import eu.etaxonomy.cdm.io.mexico.SimpleExcelTaxonImport;
22
import eu.etaxonomy.cdm.io.mexico.SimpleExcelTaxonImportState;
23
import eu.etaxonomy.cdm.model.name.Rank;
24
import eu.etaxonomy.cdm.model.name.TaxonName;
25
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
26
import eu.etaxonomy.cdm.model.reference.Reference;
27
import eu.etaxonomy.cdm.model.taxon.Classification;
28
import eu.etaxonomy.cdm.model.taxon.Taxon;
29
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
30
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
31
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
32
import eu.etaxonomy.cdm.persistence.query.MatchMode;
33

    
34
/**
35
 * @author a.mueller
36
 * @since 2018-08-09
37
 */
38

    
39
@Component
40
public class PhycobankHigherClassificationExcelImport<CONFIG extends PhycobankHigherClassificationImportConfigurator>
41
        extends SimpleExcelTaxonImport<CONFIG> {
42

    
43
    private static final long serialVersionUID = -77504409820284052L;
44
    private static final Logger logger = Logger.getLogger(PhycobankHigherClassificationExcelImport.class);
45

    
46
    private static final String GENUS = "genus";
47
    private static final String FAMILIA = "familia";
48
    private static final String SUBORDO = "subordo";
49
    private static final String ORDO = "ordo";
50
    private static final String SUBCLASSIS = "subclassis";
51
    private static final String CLASSIS = "classis";
52
    private static final String PHYLUM = "phylum";
53

    
54
    private static final List<String> propertyPaths = null;
55
    private static TaxonRelationshipType relType;
56

    
57

    
58
    @Override
59
    protected String getWorksheetName() {
60
//        return "HigherRanksEntwurfNeu";
61
        return "WoRMS";
62
    }
63

    
64
    private class RankedUninomial{
65
        public RankedUninomial(String uninomial, Rank rank) {
66
            this.uninomial = uninomial;
67
            this.rank = rank;
68
        }
69
        String uninomial;
70
        Rank rank;
71
        @Override
72
        public String toString() {
73
            return "RankedUninomial [uninomial=" + uninomial + ", rank=" + rank + "]";
74
        }
75
    }
76

    
77
    /**
78
	 *  Creates higher taxonomy
79
	 */
80
	@Override
81
    protected void firstPass(SimpleExcelTaxonImportState<CONFIG> state) {
82
	    //TODO correct?
83
	    relType = TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN();
84

    
85
	    String line = "line " + state.getCurrentLine();
86
        Map<String, String> record = state.getOriginalRecord();
87

    
88
        List<RankedUninomial> rankedUninomials = makeRankedUninomials(state, record);
89

    
90
        createOrVerifyRankedUninomials(state, rankedUninomials, line);
91

    
92
		return;
93
    }
94

    
95

    
96
    /**
97
     * For the given list of {@link RankedUninomial}s names and taxa are created
98
     * if they do not yet exist. Parent child relationships as well as concept
99
     * relationships are created if they do not yet exists.
100
     * If the data is inconsistent to existing data inconsistency is logged and
101
     * no higher classification is created.
102
     * @param state
103
     * @param rankedUninomials
104
     * @param line
105
     */
106
    private TaxonNode createOrVerifyRankedUninomials(SimpleExcelTaxonImportState<CONFIG> state,
107
            List<RankedUninomial> rankedUninomials, String line) {
108

    
109
        if (rankedUninomials.isEmpty()){
110
            return getClassification(state).getRootNode();
111
        }else{
112
            RankedUninomial rankedUninomial = rankedUninomials.get(0);
113
            rankedUninomials.remove(0);
114
            Taxon taxon = getOrMakeTaxon(state, rankedUninomial, line);
115
            TaxonNode existingNode = taxon.getTaxonNode(getClassification(state));
116
            TaxonNode existingHigherNode = existingNode == null? null : existingNode.getParent();
117
            TaxonNode createdHigher = createOrVerifyRankedUninomials(state, rankedUninomials, line);
118
//            boolean exists = verifyNextHigher(state, rankedUninomials, existingHigher);
119

    
120
            if (existingNode != null){
121
                if (existingHigherNode == null){
122
                    logger.warn(line + ": Higher node does not exist. This should not happen. Please check classification.");
123
                }else if (existingHigherNode.equals(createdHigher)){
124
                    //nothing to do;
125
                }else{
126
                    logger.warn(line + ": Inconsistency in data. Higher taxon for rank " + rankedUninomial.rank +
127
                            " differs from existing higher taxon. Higher taxonomy not created. Please check classification.");
128
                }
129
            }else { //existingNode == null
130
                if (createdHigher == null){
131
                    logger.warn(line + ": Created higher node is null. This should not happen. Please check classification and concept relationships.");
132
                    return null;
133
                }else{
134
                    existingNode = createdHigher.addChildTaxon(taxon, getSecReference(state), line);
135
                    getTaxonNodeService().saveOrUpdate(existingNode);
136
                }
137
            }
138
            makeConceptRelation(state, existingNode, line);
139
            return existingNode;
140
        }
141
    }
142
//
143
//
144
//    /**
145
//     *
146
//     * @param state
147
//     * @param rankedUninomials
148
//     * @param nextHigher
149
//     * @return
150
//     */
151
//    private boolean verifyNextHigher(SimpleExcelTaxonImportState<CONFIG> state,
152
//            List<RankedUninomial> rankedUninomials,
153
//            TaxonNode nextHigher) {
154
//        if (nextHigher == null){
155
//            return false;
156
//        }else{
157
//            boolean result = true;
158
//            RankedUninomial rankedUninomial = rankedUninomials.get(0);
159
//            TaxonName name = nextHigher.getTaxon().getName();
160
//            if (!rankedUninomial.rank.equals(name.getRank())){
161
//                result = false;
162
//            }
163
//            if (!rankedUninomial.uninomial.equals(name.getNameCache())){
164
//                result = false;
165
//            }
166
//            return result;
167
//        }
168
//    }
169

    
170

    
171
    /**
172
     * Creates a list of {@link RankedUninomial}s for the given record.
173
     * Empty fields are not listed.
174
     * @param state
175
     * @param record
176
     * @return
177
     */
178
    private List<RankedUninomial> makeRankedUninomials(
179
            SimpleExcelTaxonImportState<CONFIG> state, Map<String, String> record) {
180

    
181
        List<RankedUninomial> result = new ArrayList<>();
182
        addRankedUninomial(result, record, GENUS, Rank.GENUS());
183
        addRankedUninomial(result, record, FAMILIA, Rank.FAMILY());
184
        addRankedUninomial(result, record, SUBORDO, Rank.SUBORDER());
185
        addRankedUninomial(result, record, ORDO, Rank.ORDER());
186
        addRankedUninomial(result, record, SUBCLASSIS, Rank.SUBCLASS());
187
        addRankedUninomial(result, record, CLASSIS, Rank.CLASS());
188
        addRankedUninomial(result, record, PHYLUM, Rank.PHYLUM());
189
        return result;
190
    }
191

    
192
    /**
193
     * Creates a {@link RankedUninomial} for a given record field and
194
     * adds it to the list. If the field is empty no {@link RankedUninomial} is
195
     * created.
196
     * @param list
197
     * @param record
198
     * @param fieldName
199
     * @param rank
200
     */
201
    private void addRankedUninomial(List<RankedUninomial> list, Map<String, String> record,
202
            String fieldName, Rank rank) {
203
        String uninomial = record.get(fieldName);
204
        if (isNotBlank(uninomial)){
205
            list.add(new RankedUninomial(uninomial, rank));
206
        }
207
    }
208

    
209

    
210
    /**
211
     * @param state
212
     * @param uninomial
213
     * @param rank
214
     * @param sec
215
     * @return
216
     */
217
    protected Taxon getOrMakeTaxon(SimpleExcelTaxonImportState<CONFIG> state,
218
            RankedUninomial rankedUninomial, String line) {
219

    
220
        Reference sec = getSecReference(state);
221
        List<TaxonName> nameCandidates = getNameService().findNamesByNameCache(
222
                rankedUninomial.uninomial, MatchMode.EXACT, propertyPaths);
223
        List<TaxonName> names = rankedNames(state, nameCandidates, rankedUninomial.rank);
224

    
225
        Taxon taxon;
226
        if (names.isEmpty()){
227
            taxon = createTaxonAndName(state, rankedUninomial.uninomial,
228
                    rankedUninomial.rank, line);
229
        }else{
230
            if (names.size()> 1){
231
                List<Taxon> taxa = new ArrayList<>();
232
                for (TaxonName name : names){
233
                    taxa.addAll(getReferencedTaxa(name, sec));
234
                }
235
                if (taxa.isEmpty()){
236
                    logger.warn(line + ": More than 1 name matches, but no matching taxon exists. Create new taxon with arbitrary name.");
237
                    TaxonName name = names.get(0);
238
                    taxon = getOrCreateTaxon(state, name, sec, line);
239
                }else if (taxa.size() == 1){
240
                    taxon = taxa.get(0);
241
                }else{
242
                    logger.warn(line + ": More than 1 taxon matches, take arbitrary one. This is unexpected and could be improved in code by "
243
                            + "also checking parent relationships.");
244
                    taxon = taxa.get(0);
245
                }
246

    
247
            }else{
248
                TaxonName name = names.get(0);
249
                taxon = getOrCreateTaxon(state, name, sec, line);
250
            }
251
        }
252
        return taxon;
253
    }
254

    
255
    /**
256
     * @param state
257
     * @return
258
     */
259
    private Classification getClassification(SimpleExcelTaxonImportState<CONFIG> state) {
260
        Classification result = null;
261
        List<Classification> classifications = getClassificationService().list(null, null, null, null, null);
262
        Reference sec = getSecReference(state);
263
        for (Classification classification: classifications){
264
            if (classification.getCitation().equals(sec)){
265
                result = classification;
266
            }
267
        }
268
        if (result == null){
269
            result = Classification.NewInstance(sec.getTitleCache());
270
            result.setReference(sec);
271
            getClassificationService().save(result);
272
        }
273
        return result;
274
    }
275

    
276
    private Reference secReference;
277

    
278
    /**
279
     * @param state
280
     */
281
    private Reference getSecReference(SimpleExcelTaxonImportState<CONFIG> state) {
282
        UUID uuid = state.getConfig().getSecReference().getUuid();
283
        if (secReference == null || !secReference.getUuid().equals(uuid)){
284
            secReference = getReferenceService().find(uuid);
285
            if (secReference == null){
286
                secReference = state.getConfig().getSecReference();
287
                getReferenceService().save(secReference);
288

    
289
            }
290
        }
291
        return secReference;
292
    }
293

    
294

    
295
    /**
296
     * @param state
297
     * @param uninomial
298
     * @param rank
299
     * @param line
300
     * @return
301
     */
302
    private Taxon createTaxonAndName(SimpleExcelTaxonImportState<CONFIG> state, String uninomial,
303
            Rank rank, String line) {
304
        TaxonName newName = TaxonNameFactory.NewBotanicalInstance(rank);
305
        newName.setGenusOrUninomial(uninomial);
306
        newName.addImportSource(null, null, getSourceReference(state), line);
307

    
308
        Taxon taxon = createTaxon(state, newName, line);
309
        return taxon;
310
    }
311

    
312
    /**
313
     * @param state
314
     * @param name
315
     * @param sec
316
     * @param line
317
     * @return
318
     */
319
    private Taxon getOrCreateTaxon(SimpleExcelTaxonImportState<CONFIG> state, TaxonName name,
320
            Reference sec, String line) {
321
        List<Taxon> taxa = getReferencedTaxa(name, sec);
322
        Taxon result;
323
        if (taxa.isEmpty()){
324
            return createTaxon(state, name, line);
325
        }else{
326
            if (taxa.size()> 1){
327
                //TODO handle
328
            }
329
            result = taxa.get(0);
330
        }
331
        return result;
332
    }
333

    
334

    
335
    /**
336
     * @param name
337
     * @param sec
338
     * @return
339
     */
340
    protected List<Taxon> getReferencedTaxa(TaxonName name, Reference sec) {
341
        List<Taxon> taxa = new ArrayList<>();
342
        for (Taxon taxon : name.getTaxa()){
343
            if (sec.equals(taxon.getSec())){
344
                taxa.add(taxon);
345
            }
346
        }
347
        return taxa;
348
    }
349

    
350
    /**
351
     * @param state
352
     * @param name
353
     * @param line
354
     * @return
355
     */
356
    private Taxon createTaxon(SimpleExcelTaxonImportState<CONFIG> state,
357
            TaxonName name, String line) {
358
        Taxon taxon = Taxon.NewInstance(name, getSecReference(state));
359
        taxon.addImportSource(null, null, getSourceReference(state), line);
360
        return taxon;
361
    }
362

    
363

    
364
    /**
365
     * @param state
366
     * @param nameCandidates
367
     * @param rank
368
     * @return
369
     */
370
    private List<TaxonName> rankedNames(SimpleExcelTaxonImportState<CONFIG> state,
371
            List<TaxonName> nameCandidates,
372
            Rank rank) {
373
        List<TaxonName> result = new ArrayList<>();
374
        for (TaxonName name : nameCandidates) {
375
            if (rank.equals(name.getRank())){
376
                result.add(name);
377
            }
378
        }
379
        return result;
380
    }
381

    
382

    
383
    /**
384
     * @param state
385
     * @param childNode
386
     * @param microCitation
387
     */
388
    private void makeConceptRelation(SimpleExcelTaxonImportState<CONFIG> state,
389
            TaxonNode childNode, String microCitation) {
390
        Taxon child = childNode.getTaxon();
391
        Taxon parent = childNode.getParent().getTaxon();
392
        if (parent == null){
393
            return;
394
        }
395

    
396
        Reference sec = getSecReference(state);
397
        Set<TaxonRelationship> rels = child.getRelationsFromThisTaxon();
398
        boolean hasRelation = false;
399
        for (TaxonRelationship rel : rels){
400
            if (rel.getType().equals(relType)
401
                    && rel.getToTaxon().equals(parent)
402
                    && rel.getCitation().equals(sec)){
403
                hasRelation = true;
404
            }
405
        }
406
        if (!hasRelation){
407
            child.addTaxonRelation(parent, relType, sec, microCitation);
408
        }
409
    }
410

    
411
}
(6-6/8)