Project

General

Profile

Download (24.5 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 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
package eu.etaxonomy.cdm.io.wfo.in;
10

    
11
import java.util.HashMap;
12
import java.util.HashSet;
13
import java.util.Map;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import org.springframework.stereotype.Component;
18

    
19
import eu.etaxonomy.cdm.api.service.dto.IdentifiedEntityDTO;
20
import eu.etaxonomy.cdm.api.service.pager.Pager;
21
import eu.etaxonomy.cdm.io.csv.in.CsvImportBase;
22
import eu.etaxonomy.cdm.model.common.CdmBase;
23
import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
24
import eu.etaxonomy.cdm.model.name.Rank;
25
import eu.etaxonomy.cdm.model.name.TaxonName;
26
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
27
import eu.etaxonomy.cdm.model.reference.Reference;
28
import eu.etaxonomy.cdm.model.taxon.Classification;
29
import eu.etaxonomy.cdm.model.taxon.Synonym;
30
import eu.etaxonomy.cdm.model.taxon.SynonymType;
31
import eu.etaxonomy.cdm.model.taxon.Taxon;
32
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
33
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
34
import eu.etaxonomy.cdm.model.term.DefinedTerm;
35
import eu.etaxonomy.cdm.persistence.query.MatchMode;
36

    
37
/**
38
 * @author a.mueller
39
 * @since 15.11.2017
40
 */
41
@Component
42
public class WfoAccessClassificationImport<STATE extends WfoAccessImportState>
43
        extends CsvImportBase<WfoAccessImportConfigurator, STATE, TaxonName>{
44

    
45
    /**
46
     *
47
     */
48
    private static final String PSEUDO_SUFFIX = "_PSEUDO";
49

    
50
    /**
51
     *
52
     */
53
    private static final String WFO_DOUBTFUL = "__WFO_Doubtful";
54

    
55
    private static final long serialVersionUID = 8721691506017004260L;
56

    
57
    private static final String TAXON_ID = "taxonID";
58
    private static final String PARENT_NAME_USAGE_ID = "parentNameUsageID";
59
    private static final String FAMILY = "family";
60
    private static final String GENUS = "genus";
61
    private static final String SPECIFIC_EPITHET = "specificEpithet";
62
    private static final String INFRA_SPECIFIC_EPITHET = "infraspecificEpithet";
63
    private static final String TAXONOMIC_STATUS = "taxonomicStatus";
64
    private static final String ACCEPTED_NAME_USAGE_ID = "acceptedNameUsageID";
65
    private static final String ORIGINAL_NAME_USAGE_ID = "originalNameUsageID";
66

    
67
    private Map<String,TaxonName> nameMap;
68
    private Map<UUID, TaxonNode> pseudoParentMap;
69
    private Classification classification;
70

    
71

    
72
    public enum TaxStatus{
73
        ACC,
74
        SYN,
75
        DOUBT;
76
        public static TaxStatus from(String statusStr){
77
            if ("Accepted".equals(statusStr)){
78
                return ACC;
79
            }else if ("Synonym".equals(statusStr)){
80
                return SYN;
81
            }else if ("Doubtful".equals(statusStr)){
82
                return DOUBT;
83
            }else{
84
                throw new RuntimeException("Taxonomic status not recognized: " + statusStr);
85
            }
86
        }
87
    }
88

    
89
    /**
90
     * {@inheritDoc}
91
     */
92
    @Override
93
    protected void handleSingleLine(STATE state) {
94

    
95
        Map<String, String> record = state.getCurrentRecord();
96
        String taxonId = record.get(TAXON_ID);
97
        if (state.isExistingWfoID(taxonId)){
98
            return;
99
        }
100
        TaxonName name = getName(state, TAXON_ID);
101
        TaxStatus status =  TaxStatus.from(record.get(TAXONOMIC_STATUS));
102
        if (status == TaxStatus.ACC){
103
            handleAccepted(state, name);
104
        }else if (status == TaxStatus.SYN){
105
            handleSynonym(state, name);
106
        }else if (status == TaxStatus.DOUBT){
107
            handleDoubtful(state, name);
108
        }
109
    }
110

    
111
    /**
112
     * @param state
113
     * @param name
114
     * @param cdmTaxon
115
     */
116
    private void handleAccepted(STATE state, TaxonName name) {
117
        TaxonBase<?> cdmTaxon = getCdmTaxon(state, name, TAXON_ID, Taxon.class);
118

    
119
        Reference sec = this.getTransactionalSourceReference(state);
120
        if (cdmTaxon == null){
121
            String message = "Taxon does not exist. This should not happen.";
122
            state.getResult().addError(message, state.getRow());
123
            return;
124
        }else if (cdmTaxon.isInstanceOf(Taxon.class)){
125
            Taxon taxon = CdmBase.deproxy(cdmTaxon, Taxon.class);
126
            TaxonName parentName = getName(state, PARENT_NAME_USAGE_ID);
127
            TaxonBase<?> parentBase = getCdmTaxon(state, parentName, PARENT_NAME_USAGE_ID, Taxon.class);
128
            TaxonNode newNode;
129
            if (parentBase == null){
130
                //parent does not exist
131
                String message = "Parent taxon does not exist. This should not hapen.";
132
                state.getResult().addWarning(message, state.getRow());
133
//                TaxonNode wfoParentGenus = getWfoGenus(state, state.getCurrentRecord().get(GENUS), Rank.GENUS());
134
//                newNode = wfoParentGenus.addChildTaxon(taxon, sec, null);
135
                newNode = null;
136
            }else if (parentBase.isInstanceOf(Synonym.class)){
137
                //parent is synonym
138
//                o   >bitte die im Import-File akzeptierte Gattung [mit Suffix _wfo] als Taxon einrichten, aber ohne wfo-ID.
139
//                o   Also im Beispiel Abies_wfo als Gattung unter der Familie (zusätzlich zum Synonym Abies)
140

    
141
                //TODO
142
                Synonym synonymParent = CdmBase.deproxy(parentBase, Synonym.class);
143
                TaxonNode wfoParentGenus = getWfoGenus(state, synonymParent.getName().getNameCache(), synonymParent.getName().getRank());
144
                newNode = wfoParentGenus.addChildTaxon(taxon, sec, null);
145
            }else{ //existing parent is accepted
146
                Taxon parentTaxon = CdmBase.deproxy(parentBase, Taxon.class);
147
                Set<TaxonNode> parentNodes = parentTaxon.getTaxonNodes();
148
                if (parentNodes.size() == 0){
149
                    //TODO
150
                    Classification classification = getClassification(state);
151
                    newNode = classification.addParentChild(parentTaxon, taxon, sec, null);
152
                    getTaxonNodeService().saveOrUpdate(newNode.getParent());
153
                }else if (parentNodes.size() == 1){
154
                    Classification classification = getClassification(state);
155
                    newNode = classification.addParentChild(parentTaxon, taxon, sec, null);
156
                    getTaxonNodeService().saveOrUpdate(newNode.getParent());
157
//                    newNode = parentNodes.iterator().next().addChildTaxon(taxon, sec, null);
158
                }else{//multiple nodes for parent taxon
159
                    String message = "Parent taxon belongs to multiple nodes. This is unexpected and not handled. Add new node to classification";
160
                    state.getResult().addWarning(message, state.getRow());
161
                    Classification classification = getClassification(state);
162
                    newNode = classification.addParentChild(parentTaxon, taxon, sec, null);
163
                }
164
            }
165
            if (newNode != null){
166
                getTaxonNodeService().save(newNode);
167
            }
168

    
169
            //handle basionym
170
            if (state.getCurrentRecord().get(ORIGINAL_NAME_USAGE_ID)!= null){
171
                TaxonName basionym;
172
                try {
173
                    basionym = getName(state, ORIGINAL_NAME_USAGE_ID);
174
                    name.addBasionym(basionym, sec, null, null);
175
                    TaxonBase<?> basionymTaxon = getCdmTaxon(state, basionym, ORIGINAL_NAME_USAGE_ID, Synonym.class);
176
                    if (basionymTaxon.isInstanceOf(Synonym.class)){
177
                        Synonym basioSynonym = CdmBase.deproxy(basionymTaxon, Synonym.class);
178
                        if (basioSynonym.getAcceptedTaxon() != null){
179
                            if (basioSynonym.getAcceptedTaxon().equals(taxon)){
180
                                basioSynonym.setType(SynonymType.HOMOTYPIC_SYNONYM_OF());
181
                            }else{
182
                                String message = "Taxon's basionym already has an accepted taxon (%s), but the accepted taxon is not this taxon (%s).";
183
                                message = String.format(message, basioSynonym.getAcceptedTaxon().getTitleCache(), taxon.getTitleCache());
184
                                state.getResult().addError(message, state.getRow());
185
                            }
186
                        }else{
187
                            taxon.addHomotypicSynonym(basioSynonym);
188
                        }
189
                    }else{
190
                        String message = "Basionym %s of accepted %s is also accepted. This should not happen";
191
                        message = String.format(message, basionymTaxon.getName().getTitleCache(), taxon.getName().getTitleCache());
192
                        state.getResult().addWarning(message, state.getRow());
193
                    }
194
                } catch (Exception e) {
195
                    String message = "Problem when handling basionym for " + name.getTitleCache();
196
                    state.getResult().addError(message, state.getRow());
197
                }
198
            }
199
        }else{
200
            String message = "TaxonBase of accepted name is synonym. This should not happen anymore";
201
            state.getResult().addError(message, state.getRow());
202
        }
203
    }
204

    
205

    
206
    /**
207
     * @param state
208
     * @return
209
     */
210
    private Classification getClassification(STATE state) {
211
        if (classification == null){
212
            //TODO FIXME quick and dirty
213
            UUID uuidClassification = UUID.fromString("9edc58b5-de3b-43aa-9f31-1ede7c009c2b");
214
            classification = getClassificationService().find(uuidClassification);
215
            if (classification == null){
216
                String message = "Classification could not be found.";
217
                state.getResult().addError(message, state.getRow());
218
                throw new RuntimeException(message);
219
            }
220
        }
221
        return classification;
222
    }
223

    
224
    /**
225
     * @param state
226
     * @return
227
     */
228
    private TaxonNode getWfoGenus(STATE state, String taxonName, Rank rank) {
229
        Map<String, String> record = state.getCurrentRecord();
230
        String key = taxonName + "WFO";
231
        UUID uuid = state.getTaxonNodeUuid(key);
232
        TaxonNode node = getTaxonNodeMap().get(uuid);
233
        if (uuid != null && node == null){
234
            node = getTaxonNodeService().find(uuid);
235
            if (node != null){
236
                getTaxonNodeMap().put(node.getUuid(), node);
237
            }
238
        }
239
        if (node == null){
240
            if (uuid != null){
241
                String message = "Node for given parent uuid does not exist. This should not happen.";
242
                state.getResult().addWarning(message, state.getRow());
243
            }
244
            Reference sec = this.getTransactionalSourceReference(state);
245
            TaxonName name = TaxonNameFactory.NewNameInstance(state.getConfig().getNomenclaturalCode(), Rank.GENUS());
246
            name.setTitleCache(taxonName + "_WFO", true);
247
            addSourceReference(state, name);
248

    
249
            Taxon wfoTaxon = Taxon.NewInstance(name, sec);
250
            addSourceReference(state, wfoTaxon);
251

    
252
            TaxonNode familyNode = getFamilyParent(state, record.get(FAMILY));
253
            node = familyNode.addChildTaxon(wfoTaxon, sec, null);
254
            state.putTaxonNodeUuid(key, node.getUuid());
255
            getTaxonNodeMap().put(node.getUuid(), node);
256
            getTaxonNodeService().save(node);
257
        }
258
        return node;
259
    }
260

    
261
    /**
262
     * @param state
263
     * @param name
264
     * @param cdmTaxon
265
     */
266
    private void handleSynonym(STATE state, TaxonName name) {
267
        TaxonBase<?> cdmTaxon = getCdmTaxon(state, name, TAXON_ID, Synonym.class);
268

    
269
        if (cdmTaxon == null){
270
            String message = "Synonym does not exist. This should not happen.";
271
            state.getResult().addError(message, state.getRow());
272
        }else if (cdmTaxon.isInstanceOf(Synonym.class)){
273
            Synonym syn = CdmBase.deproxy(cdmTaxon, Synonym.class);
274
            TaxonName accName = getName(state, ACCEPTED_NAME_USAGE_ID);
275

    
276
            if (syn.getAcceptedTaxon()== null){
277
                 //TODO is this correct? might be WFO taxon
278
                TaxonBase<?> existingAccepted = getCdmTaxon(state, accName, ACCEPTED_NAME_USAGE_ID, Taxon.class);
279
                Taxon taxon;
280
                if (existingAccepted == null){
281
                    String message = "Accepted taxon does not exist. Can't add synonym to accepted";
282
                    state.getResult().addError(message, state.getRow());
283
                    taxon = null; //or throw exception
284
                }else if (existingAccepted.isInstanceOf(Synonym.class)){
285
                    Synonym existingSynonym = CdmBase.deproxy(existingAccepted, Synonym.class);
286
                    taxon = existingSynonym.getAcceptedTaxon();
287
                    taxon.addSynonym(syn, SynonymType.HETEROTYPIC_SYNONYM_OF());
288
                }else{
289
                    taxon = CdmBase.deproxy(existingAccepted, Taxon.class);
290
                }
291
                if (taxon != null){
292
                    taxon.addSynonym(syn, SynonymType.HETEROTYPIC_SYNONYM_OF());
293
                }
294
            }else{ //accepted taxon exists
295
                Taxon taxon = syn.getAcceptedTaxon();
296
                if (!taxon.getName().equals(accName)){
297
                    String message = "Synonym already has an accepted taxon (%s), but the accepted taxon is not the expected one (%s).";
298
                    message = String.format(message, taxon.getTitleCache(), accName.getTitleCache());
299
                    state.getResult().addError(message, state.getRow());
300
                }
301
            }
302

    
303
            //handle basionym
304
            if (state.getCurrentRecord().get(ORIGINAL_NAME_USAGE_ID)!= null){
305
                try{
306
                    TaxonName basionym = getName(state, ORIGINAL_NAME_USAGE_ID);
307
                    name.addBasionym(basionym, getTransactionalSourceReference(state), null, null);
308

    
309
                    TaxonBase<?> basionymTaxon = getCdmTaxon(state, basionym, ORIGINAL_NAME_USAGE_ID, TaxonBase.class);
310
                    if (basionymTaxon.isInstanceOf(Taxon.class)){
311
                        Taxon basioTaxon = CdmBase.deproxy(basionymTaxon, Taxon.class);
312
                        if (syn.getAcceptedTaxon().equals(basioTaxon)){
313
                            syn.setType(SynonymType.HOMOTYPIC_SYNONYM_OF());
314
                        }else{
315
                            String message = "Synonyms(%s) basionym is accepted (%s), but synonym has another accepted taxon (%s).";
316
                            message = String.format(message, syn.getName().getTitleCache(), basionymTaxon.getName().getTitleCache(),
317
                                    syn.getAcceptedTaxon().getName().getTitleCache());
318
                            state.getResult().addError(message, state.getRow());
319
                        }
320
                    }else{
321
                        //basionym is also synonym, for now nothing to do
322
                    }
323
                } catch (Exception e) {
324
                    String message = "Problem when handling basionym for " + name.getTitleCache();
325
                    state.getResult().addError(message, state.getRow());
326
                }
327
            }
328
        }else{  //is accepted
329
            String message = "TaxonBase of synonym is accepted. This should not happen anymore";
330
            state.getResult().addError(message, state.getRow());
331
        }
332
    }
333

    
334
    /**
335
     * @param state
336
     * @param name
337
     * @param taxonId
338
     * @return
339
     */
340
    private TaxonBase<?> getCdmTaxon(STATE state, TaxonName name, String fieldName,
341
            Class<? extends TaxonBase> expectedClass) {
342
        Map<String, String> record = state.getCurrentRecord();
343
        String taxonId = record.get(fieldName);
344

    
345
        @SuppressWarnings("rawtypes")
346
        Set<TaxonBase> cdmTaxa = name.getTaxonBases();
347
        if (cdmTaxa.isEmpty()){
348
            return null;
349
        }else if (cdmTaxa.size()==1){
350
            return cdmTaxa.iterator().next();
351
        }else{
352
            Set<TaxonBase<?>> cdmTaxa2 = new HashSet<>();
353
            for (TaxonBase<?> x : cdmTaxa){
354
                if (x.isInstanceOf(expectedClass)){
355
                    cdmTaxa2.add(x);
356
                }
357
            }
358
            if (cdmTaxa2.size() == 1){
359
                //TODO preliminary
360
                return cdmTaxa2.iterator().next();
361
            }
362
            String message = "Name %s (%s) has more then 1 existing taxon. Can't define existing taxon. Return arbitrary.";
363
            message = String.format(message, name.getTitleCache(), taxonId);
364
            state.getResult().addError(message, state.getRow());
365
            return cdmTaxa.iterator().next();
366
        }
367
    }
368

    
369
    /**
370
     * @param state
371
     * @param name
372
     * @param cdmTaxon
373
     */
374
    private void handleDoubtful(STATE state, TaxonName name) {
375
        TaxonBase<?> cdmTaxon = getCdmTaxon(state, name, TAXON_ID, Taxon.class);
376

    
377
        Reference sec = getTransactionalSourceReference(state);
378
//        Map<String, String> record = state.getCurrentRecord();
379
//        String taxonId = record.get(TAXON_ID);
380
//        if (state.isOriginalNameOfDoubful(taxonId)) {
381
//            //will be handled with doubtful accepted
382
//            //newTaxon = Synonym.NewInstance(name, sec);
383
//
384
//        }else{
385
//            Taxon newTaxon = Taxon.NewInstance(name, sec);
386
//            addSourceReference(state, newTaxon);
387
//            newTaxon.setDoubtful(true);
388
        if (cdmTaxon.isInstanceOf(Synonym.class)){
389
            String message = "Doubtful taxon was synonym. This should not happen";
390
            state.getResult().addError(message, state.getRow());
391
        }else{
392
            Taxon taxon = CdmBase.deproxy(cdmTaxon, Taxon.class);
393
            TaxonNode parent = getDoubtfulPseudoParent(state, sec);
394
            TaxonNode newChild = parent.addChildTaxon(taxon, sec, null);
395
            String originalNameIdStr = state.getCurrentRecord().get(ORIGINAL_NAME_USAGE_ID);
396
            if (isNotBlank(originalNameIdStr)){
397
//                TaxonName basionym = makeDoubtfulBasionym(state, ORIGINAL_NAME_USAGE_ID, sec);
398
                  try {
399
                      TaxonName basionym = getName(state, ORIGINAL_NAME_USAGE_ID);
400
                      name.addBasionym(basionym, sec, null, null);
401
                } catch (Exception e) {
402
                    String message = "Problem when handling basionym for " + name.getTitleCache();
403
                    state.getResult().addError(message, state.getRow());
404
                }
405
//                Synonym synonym = newTaxon.addHomotypicSynonymName(basionym);
406
//                synonym.setDoubtful(true);
407
//                addSourceReference(state, synonym);
408
            }
409
            getTaxonNodeService().saveOrUpdate(newChild);
410

    
411
        }
412
//        }
413
}
414

    
415

    
416

    
417
    /**
418
     * @param state
419
     * @param originalNameStr
420
     * @param sec
421
     * @return
422
     */
423
    private TaxonName makeDoubtfulBasionym(STATE state, String attrName, Reference sec) {
424
        TaxonName basionymName = getName(state, attrName);
425
        if (basionymName.getTaxonBases().size()>0){
426
            String message = "Doubtful basionym should not have a taxon attached yet: " + basionymName.getTitleCache();
427
            state.getResult().addError(message, state.getRow());
428
        }
429
        return basionymName;
430
    }
431

    
432
    /**
433
     * @param state
434
     * @return
435
     */
436
    private TaxonNode getDoubtfulPseudoParent(STATE state, Reference sec) {
437
        Map<String, String> record = state.getCurrentRecord();
438
        String family = record.get(FAMILY);
439
        String familyPseudo = family + PSEUDO_SUFFIX;
440
        UUID pseudoUuid = state.getTaxonNodeUuid(familyPseudo);
441
        TaxonNode pseudoParent = getTaxonNodeMap().get(pseudoUuid);
442
        if (pseudoParent == null){
443
            pseudoParent = getTaxonNodeService().find(pseudoUuid);
444
        }
445
        if (pseudoParent == null){
446
            TaxonNode familyParent = getFamilyParent(state, family);
447
            TaxonName pseudoName = TaxonNameFactory.NewNameInstance(state.getConfig().getNomenclaturalCode(),
448
                    Rank.SUPRAGENERICTAXON());
449
            addSourceReference(state, pseudoName);
450

    
451
            pseudoName.setTitleCache(WFO_DOUBTFUL + "_" + family, true);
452
            Taxon pseudoTaxon = Taxon.NewInstance(pseudoName, sec);
453
            addSourceReference(state, pseudoTaxon);
454

    
455
            pseudoParent = familyParent.addChildTaxon(pseudoTaxon, sec, null);
456
            state.putTaxonNodeUuid(familyPseudo, pseudoParent.getUuid());
457
            getTaxonNodeService().save(pseudoParent);
458
        }
459
        getTaxonNodeMap().put(pseudoParent.getUuid(), pseudoParent);  // in case not yet in
460
        return pseudoParent;
461
    }
462

    
463
    /**
464
     * @param state
465
     * @param family2
466
     * @return
467
     */
468
    private TaxonNode getFamilyParent(STATE state, String familyStr) {
469
        //FIXME TODO nasty quick and dirty find uuid for families/Dianthus
470
        UUID familyUuid;
471
        if (familyStr.equals("Amaranthaceae")){
472
            familyUuid = UUID.fromString("5f778f37-c60e-45e4-a3b3-123eec218428");
473
        }else if (familyStr.equals("Caryophyllaceae")){
474
            familyUuid = UUID.fromString("9078bb8e-eb68-4944-8a81-e855bfbe20c6"); //is Dianthus uuid
475
        }else if (familyStr.equals("Chenopodiaceae")){
476
            familyUuid = UUID.fromString("dec80465-49ca-47d7-9280-863bcb891877");
477
        }else if (familyStr.equals("Polygonaceae")){
478
            familyUuid = UUID.fromString("e2c836db-8ff3-42c5-ae76-60cd5da2bd0c");
479
        }else{
480
            String message = "Family not yet handled in code: " +  familyStr;
481
            throw new RuntimeException(message);
482
        }
483
        TaxonNode familyNode = getTaxonNodeMap().get(familyStr);
484
        if (familyNode == null){
485
            familyNode = getTaxonNodeService().find(familyUuid);
486
            getTaxonNodeMap().put(familyUuid, familyNode);
487
        }
488
        if (familyNode == null){
489
            String message = "Family node not found in database: " +  familyStr;
490
            throw new RuntimeException(message);
491
        }
492
        return familyNode;
493
    }
494

    
495
    /**
496
     * @param state
497
     * @return
498
     */
499
    private TaxonName getName(STATE state, String attr) {
500
        Map<String, String> record = state.getCurrentRecord();
501

    
502
        String taxonId = record.get(attr);
503
        TaxonName name;
504
        if (taxonId != null){
505
            name = getNameMap(state).get(taxonId);
506
//            name = getExistingTaxonName(state, taxonId);
507
        }else{
508
            String message = "TaxonID could not be found. Maybe format needs to be changed to UTF8 without BOM";
509
            state.getResult().addError(message, state.getRow());
510
            throw new RuntimeException(message);
511
//            name = null;
512
        }
513
        if (name != null){
514
            return name;
515
        }else{
516
            String message = "Taxon name for taxonID %s could not be found. This must not happen during taxon import phase.";
517
            message = String.format(message, taxonId);
518
            state.getResult().addError(message, state.getRow());
519
            throw new RuntimeException(message);
520
        }
521
    }
522

    
523

    
524
    /**
525
     * @param state
526
     * @return
527
     */
528
    private Map<String, TaxonName> getNameMap(STATE state) {
529
        if (nameMap == null){
530
            refreshNameMap(state);
531
        }
532
        return nameMap;
533
    }
534

    
535
    private Map<UUID, TaxonNode> getTaxonNodeMap() {
536
        if (pseudoParentMap == null){
537
            pseudoParentMap = new HashMap<>();
538
        }
539
        return pseudoParentMap;
540
    }
541

    
542

    
543

    
544
    /**
545
     * @param state
546
     * @param name
547
     */
548
    private void addSourceReference(STATE state, IdentifiableEntity<?> entity) {
549
        entity.addImportSource(null, null, getTransactionalSourceReference(state), "line " + state.getLine());
550
    }
551

    
552

    
553
    @Override
554
    protected void refreshTransactionStatus(STATE state) {
555
        super.refreshTransactionStatus(state);
556
        refreshNameMap(state);
557
        pseudoParentMap = new HashMap<>();
558
        classification = null;
559

    
560
    }
561

    
562

    
563
    /**
564
     * @param state
565
     */
566
    protected void refreshNameMap(STATE state) {
567
        nameMap = new HashMap<>();
568
        DefinedTerm wfoType = DefinedTerm.IDENTIFIER_NAME_WFO();
569
        Pager<IdentifiedEntityDTO<TaxonName>> identifiedNamePager = getNameService().findByIdentifier(TaxonName.class,
570
                "*", wfoType, MatchMode.EXACT, true, null, null, null);
571
        for (IdentifiedEntityDTO<TaxonName> dto : identifiedNamePager.getRecords()){
572
            TaxonName name = dto.getCdmEntity().getEntity();
573
            String identifier = dto.getIdentifier().getIdentifier();
574
            TaxonName oldName = nameMap.put(identifier, name);
575
            if (oldName != null){
576
                String message = "There are multiple names with same WFO identifier %s. ID1=%d, ID2=%d";
577
                message = String.format(message, identifier, name.getId(), oldName.getId());
578
                state.getResult().addWarning(message, state.getRow());
579
            }
580
        }
581
    }
582

    
583

    
584
}
(1-1/4)