Project

General

Profile

Download (14.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
    private Reference secReference;
58
    private Reference phycobankReference;
59

    
60

    
61
    @Override
62
    protected String getWorksheetName(CONFIG config) {
63
        return config.getWorksheetName();
64
    }
65

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

    
79
    /**
80
	 *  Creates higher taxonomy
81
	 */
82
	@Override
83
    protected void firstPass(SimpleExcelTaxonImportState<CONFIG> state) {
84

    
85
	    @SuppressWarnings("deprecation")
86
        TaxonRelationshipType type = TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN();
87
	    relType = type;
88

    
89
	    String line = "line " + state.getCurrentLine();
90
	    System.out.println(line);
91

    
92
        Map<String, String> record = state.getOriginalRecord();
93

    
94
        List<RankedUninomial> rankedUninomials = makeRankedUninomials(state, record);
95

    
96
        createOrVerifyRankedUninomials(state, rankedUninomials, line);
97

    
98
		return;
99
    }
100

    
101

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

    
115
        if (rankedUninomials.isEmpty()){
116
            return getClassification(state).getRootNode();
117
        }else{
118
            RankedUninomial rankedUninomial = rankedUninomials.get(0);
119
            rankedUninomials.remove(0);
120
            Taxon taxon = getOrMakeTaxon(state, rankedUninomial, line);
121
            TaxonNode existingNode = taxon.getTaxonNode(getClassification(state));
122
            TaxonNode existingHigherNode = existingNode == null? null : existingNode.getParent();
123
            //recursive call
124
            TaxonNode createdHigher = createOrVerifyRankedUninomials(state, rankedUninomials, line);
125
//            boolean exists = verifyNextHigher(state, rankedUninomials, existingHigher);
126

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

    
177

    
178
    /**
179
     * Creates a list of {@link RankedUninomial}s for the given record.
180
     * Empty fields are not listed.
181
     * @param state
182
     * @param record
183
     * @return
184
     */
185
    private List<RankedUninomial> makeRankedUninomials(
186
            SimpleExcelTaxonImportState<CONFIG> state, Map<String, String> record) {
187

    
188
        List<RankedUninomial> result = new ArrayList<>();
189
        addRankedUninomial(result, record, GENUS, Rank.GENUS());
190
        addRankedUninomial(result, record, FAMILIA, Rank.FAMILY());
191
        addRankedUninomial(result, record, SUBORDO, Rank.SUBORDER());
192
        addRankedUninomial(result, record, ORDO, Rank.ORDER());
193
        addRankedUninomial(result, record, SUBCLASSIS, Rank.SUBCLASS());
194
        addRankedUninomial(result, record, CLASSIS, Rank.CLASS());
195
        addRankedUninomial(result, record, PHYLUM, Rank.PHYLUM());
196
        return result;
197
    }
198

    
199
    /**
200
     * Creates a {@link RankedUninomial} for a given record field and
201
     * adds it to the list. If the field is empty no {@link RankedUninomial} is
202
     * created.
203
     * @param list
204
     * @param record
205
     * @param fieldName
206
     * @param rank
207
     */
208
    private void addRankedUninomial(List<RankedUninomial> list, Map<String, String> record,
209
            String fieldName, Rank rank) {
210
        String uninomial = record.get(fieldName);
211
        if (isNotBlank(uninomial)){
212
            list.add(new RankedUninomial(uninomial.trim(), rank));
213
        }
214
    }
215

    
216

    
217
    /**
218
     * @param state
219
     * @param uninomial
220
     * @param rank
221
     * @param sec
222
     * @return
223
     */
224
    protected Taxon getOrMakeTaxon(SimpleExcelTaxonImportState<CONFIG> state,
225
            RankedUninomial rankedUninomial, String line) {
226

    
227
        Reference phycobankRef = getPhycobankReference(state);
228
        List<TaxonName> nameCandidates = getNameService().findNamesByNameCache(
229
                rankedUninomial.uninomial, MatchMode.EXACT, propertyPaths);
230
        List<TaxonName> names = rankedNames(state, nameCandidates, rankedUninomial.rank);
231

    
232
        Taxon taxon;
233
        if (names.isEmpty()){
234
            taxon = createTaxonAndName(state, rankedUninomial.uninomial,
235
                    rankedUninomial.rank, line);
236
        }else{
237
            if (names.size() > 1){
238
                List<Taxon> taxa = new ArrayList<>();
239
                for (TaxonName name : names){
240
                    taxa.addAll(getReferencedTaxa(name, state.getConfig().getPhycobankReference()));
241
                }
242
                if (taxa.isEmpty()){
243
                    logger.warn(line + ": More than 1 name matches, but no matching taxon exists. Create new taxon with arbitrary name.");
244
                    TaxonName name = names.get(0);
245
                    taxon = getOrCreateTaxon(state, name, phycobankRef, line);
246
                }else if (taxa.size() == 1){
247
                    taxon = taxa.get(0);
248
                }else{
249
                    logger.warn(line + ": More than 1 taxon matches, take arbitrary one. This is unexpected and could be improved in code by "
250
                            + "also checking parent relationships.");
251
                    taxon = taxa.get(0);
252
                }
253
            }else{
254
                TaxonName name = names.get(0);
255
                taxon = getOrCreateTaxon(state, name, phycobankRef, line);
256
            }
257
        }
258
        return taxon;
259
    }
260

    
261
    /**
262
     * @param state
263
     * @return
264
     */
265
    private Classification getClassification(SimpleExcelTaxonImportState<CONFIG> state) {
266
        Classification result = null;
267
        List<Classification> classifications = getClassificationService().list(null, null, null, null, null);
268
        Reference sec = getSecReference(state);
269
        for (Classification classification: classifications){
270
            if (classification.getCitation() != null && classification.getCitation().equals(sec)){
271
                result = classification;
272
            }
273
        }
274
        if (result == null){
275
            result = Classification.NewInstance(sec.getTitleCache());
276
            result.setReference(sec);
277
            getClassificationService().save(result);
278
        }
279
        return result;
280
    }
281

    
282

    
283
    /**
284
     * @param state
285
     */
286
    private Reference getSecReference(SimpleExcelTaxonImportState<CONFIG> state) {
287
        UUID uuid = state.getConfig().getSecReference().getUuid();
288
        if (secReference == null || !secReference.getUuid().equals(uuid)){
289
            secReference = getReferenceService().find(uuid);
290
            if (secReference == null){
291
                secReference = state.getConfig().getSecReference();
292
                getReferenceService().save(secReference);
293

    
294
            }
295
        }
296
        return secReference;
297
    }
298

    
299
    private Reference getPhycobankReference(SimpleExcelTaxonImportState<CONFIG> state) {
300
        UUID uuid = state.getConfig().getPhycobankReference().getUuid();
301
        if (phycobankReference == null || !phycobankReference.getUuid().equals(uuid)){
302
            phycobankReference = getReferenceService().find(uuid);
303
            if (phycobankReference == null){
304
                phycobankReference = state.getConfig().getPhycobankReference();
305
                getReferenceService().save(phycobankReference);
306

    
307
            }
308
        }
309
        return phycobankReference;
310
    }
311

    
312

    
313
    /**
314
     * @param state
315
     * @param uninomial
316
     * @param rank
317
     * @param line
318
     * @return
319
     */
320
    private Taxon createTaxonAndName(SimpleExcelTaxonImportState<CONFIG> state, String uninomial,
321
            Rank rank, String line) {
322
        TaxonName newName = TaxonNameFactory.NewBotanicalInstance(rank);
323
        newName.setGenusOrUninomial(uninomial);
324

    
325
        newName.addPrimaryTaxonomicSource(getSourceReference(state));
326
        newName.addImportSource(null, null, getSourceReference(state), line);
327

    
328
        Taxon taxon = createTaxon(state, newName, line);
329
        return taxon;
330
    }
331

    
332
    /**
333
     * @param state
334
     * @param name
335
     * @param sec
336
     * @param line
337
     * @return
338
     */
339
    private Taxon getOrCreateTaxon(SimpleExcelTaxonImportState<CONFIG> state, TaxonName name,
340
            Reference phycobankRef, String line) {
341
        List<Taxon> taxa = getReferencedTaxa(name, phycobankRef);
342
        Taxon result;
343
        if (taxa.isEmpty()){
344
            return createTaxon(state, name, line);
345
        }else{
346
            if (taxa.size()> 1){
347
                logger.warn(line + ": More then 1 taxon matches for given name. Take arbitrary one.");
348
            }
349
            result = taxa.get(0);
350
        }
351
        return result;
352
    }
353

    
354

    
355
    /**
356
     * @param name
357
     * @param sec
358
     * @return
359
     */
360
    protected List<Taxon> getReferencedTaxa(TaxonName name, Reference sec) {
361
        List<Taxon> taxa = new ArrayList<>();
362
        for (Taxon taxon : name.getTaxa()){
363
            if (sec.equals(taxon.getSec())){
364
                taxa.add(taxon);
365
            }
366
        }
367
        return taxa;
368
    }
369

    
370
    /**
371
     * @param state
372
     * @param name
373
     * @param line
374
     * @return
375
     */
376
    private Taxon createTaxon(SimpleExcelTaxonImportState<CONFIG> state,
377
            TaxonName name, String line) {
378
        Taxon taxon = Taxon.NewInstance(name, getPhycobankReference(state));
379
        taxon.addImportSource(null, null, getSourceReference(state), line);
380
        return taxon;
381
    }
382

    
383

    
384
    /**
385
     * Returns those names that match in rank
386
     * @return
387
     */
388
    private List<TaxonName> rankedNames(SimpleExcelTaxonImportState<CONFIG> state,
389
            List<TaxonName> nameCandidates,
390
            Rank rank) {
391
        List<TaxonName> result = new ArrayList<>();
392
        for (TaxonName name : nameCandidates) {
393
            if (rank.equals(name.getRank())){
394
                result.add(name);
395
            }
396
        }
397
        return result;
398
    }
399

    
400

    
401
    /**
402
     * @param state
403
     * @param childNode
404
     * @param microCitation
405
     */
406
    private void makeConceptRelation(SimpleExcelTaxonImportState<CONFIG> state,
407
            TaxonNode childNode, String microCitation) {
408

    
409
        Taxon child = childNode.getTaxon();
410
        Taxon parent = childNode.getParent().getTaxon();
411
        if (parent == null){
412
            return;
413
        }
414

    
415
        Reference sec = getSecReference(state);
416
        Set<TaxonRelationship> rels = child.getRelationsFromThisTaxon();
417
        boolean hasRelation = false;
418
        for (TaxonRelationship rel : rels){
419
            if (rel.getType().equals(relType)
420
                    && rel.getToTaxon().equals(parent)
421
                    && rel.getCitation().equals(sec)){
422
                hasRelation = true;
423
            }
424
        }
425
        if (!hasRelation){
426
            child.addTaxonRelation(parent, relType, sec, microCitation);
427
        }
428
    }
429

    
430
}
(6-6/8)