Project

General

Profile

Download (19.9 KB) Statistics
| Branch: | Revision:
1
/**
2
* Copyright (C) 2016 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.mexico;
10

    
11
import java.util.Arrays;
12
import java.util.HashMap;
13
import java.util.Iterator;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Set;
17
import java.util.UUID;
18

    
19
import org.apache.commons.lang3.StringUtils;
20
import org.apache.log4j.Logger;
21
import org.springframework.stereotype.Component;
22

    
23
import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
24
import eu.etaxonomy.cdm.model.agent.Person;
25
import eu.etaxonomy.cdm.model.agent.Team;
26
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
27
import eu.etaxonomy.cdm.model.common.Annotation;
28
import eu.etaxonomy.cdm.model.common.AnnotationType;
29
import eu.etaxonomy.cdm.model.common.CdmBase;
30
import eu.etaxonomy.cdm.model.common.Extension;
31
import eu.etaxonomy.cdm.model.common.ExtensionType;
32
import eu.etaxonomy.cdm.model.common.Language;
33
import eu.etaxonomy.cdm.model.common.VerbatimTimePeriod;
34
import eu.etaxonomy.cdm.model.name.IBotanicalName;
35
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
36
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
37
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
38
import eu.etaxonomy.cdm.model.name.Rank;
39
import eu.etaxonomy.cdm.model.name.TaxonName;
40
import eu.etaxonomy.cdm.model.reference.INomenclaturalReference;
41
import eu.etaxonomy.cdm.model.reference.Reference;
42
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
43
import eu.etaxonomy.cdm.model.reference.ReferenceType;
44
import eu.etaxonomy.cdm.model.taxon.Classification;
45
import eu.etaxonomy.cdm.model.taxon.Synonym;
46
import eu.etaxonomy.cdm.model.taxon.SynonymType;
47
import eu.etaxonomy.cdm.model.taxon.Taxon;
48
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
49
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
50
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
51
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
52
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
53

    
54
/**
55
 * @author a.mueller
56
 * @since 16.06.2016
57
 *
58
 */
59
@Component
60
public class MexicoConabioTaxonImport<CONFIG extends MexicoConabioImportConfigurator>
61
        extends SimpleExcelTaxonImport<CONFIG>{
62

    
63
    private static final long serialVersionUID = 3691221053127007258L;
64

    
65
    private static final Logger logger = Logger.getLogger(MexicoConabioTaxonImport.class);
66

    
67
    public static final String TAXON_NAMESPACE = "Taxonomia";
68

    
69
    @Override
70
    protected String getWorksheetName(CONFIG  config) {
71
        return "Taxonomia";
72
    }
73

    
74
    //dirty I know, but who cares, needed by distribution and commmon name import
75
    protected static final Map<String, TaxonBase<?>> taxonIdMap = new HashMap<>();
76

    
77
    private Classification classification;
78

    
79

    
80
    private  static List<String> expectedKeys= Arrays.asList(new String[]{
81
            "IdCAT","IdCATRel","IdCAT_AscendenteInmediato"
82
            ,"IdCAT_AscendenteObligatorio","CategoriaTaxonomica","Nombre",
83
            "EstatusNombre","AutorNombre","AutorSinAnio","Anio",
84
            "ReferenciaNombre",
85
            "Division","AutorDivision","ReferenciaClasificacionDivision",
86
            "Clase","AutorClase","ReferenciaClasificacionClase",
87
            "Subclase","AutorSubclase","ReferenciaClasificacionSubclase",
88
            "Superorden","AutorSuperorden","ReferenciaClasificacionSuperorden",
89
            "Orden","AutorOrden","ReferenciaClasificacionOrden",
90
            "Familia",     "EstatusFamilia","AutorFamilia","ReferenciaClasificacionFamilia",
91
            "Tribu",  "EstatusTribu","AutorTribu","ReferenciaNombreTribu",
92
            "Genero","EstatusGenero","AutorGenero","","ReferenciaNombreGenero",
93
            "Epiteto_especifico","EstatusEspecie","AutorEpiteto_especifico","ReferenciaNombreEspecie",
94
            "CategoriaInfraespecifica","NombreInfraespecifico","EstatusInfraespecie","AutorInfraespecie","ReferenciaNombreInfraespecifico",
95
            "CitaNomenclatural","Anotacion al Taxon","Fuente_BDs",
96
            "FamAceptada","GenAceptado","CategoriaTaxAceptada","NombreAceptado","AutorNombreAceptado","AutorSinAnioAceptado","AnioAceptado",
97
            "TipoRelacion","ReferenciaSinonimia","ComentariosRevisor",
98
            "CompareID","IdCAT_OLD","Nombre_OLD","AutorSinAnio_OLD",
99
            "CitaNomenclatural_OLD","ReferenceType","IsUpdated"
100
        });
101

    
102

    
103
    @Override
104
    protected void firstPass(SimpleExcelTaxonImportState<CONFIG> state) {
105
        String line = state.getCurrentLine() + ": ";
106
        Map<String, String> record = state.getOriginalRecord();
107

    
108
        Set<String> keys = record.keySet();
109

    
110
        checkAllKeysExist(line, keys, expectedKeys);
111

    
112
        if (getValue(record, "Nombre") == null ){
113
            logger.warn("No FullnameNoAuthors given: " + line);
114
            return;
115
        }
116

    
117
        //Name
118
        IBotanicalName speciesName = makeName(line, record, state);
119

    
120
        //sec
121
        String secRefStr = getValueNd(record, "ReferenciaNombre");
122
        Reference sec = getSecRef(state, secRefStr, line);
123

    
124
        //status
125
        String statusStr = getValue(record, "EstatusNombre");
126
        TaxonBase<?> taxonBase;
127
        if ("aceptado".equals(statusStr)){
128
            taxonBase = Taxon.NewInstance(speciesName, sec);
129
        }else if (statusStr.startsWith("sin")){
130
            taxonBase = Synonym.NewInstance(speciesName, sec);
131
        }else{
132
            throw new RuntimeException(line + " Status not recognized: " + statusStr);
133
        }
134

    
135
        //annotation
136
        String annotation = getValue(record, "Anotacion al Taxon");
137
        if (annotation != null && (!annotation.equals("nom. illeg.") || !annotation.equals("nom. cons."))){
138
            taxonBase.addAnnotation(Annotation.NewInstance(annotation, AnnotationType.EDITORIAL(), Language.SPANISH_CASTILIAN()));
139
        }
140

    
141
        //id
142
        String idCat = getValue(record, "IdCAT");
143
        this.addOriginalSource(taxonBase, idCat, TAXON_NAMESPACE, state.getConfig().getSourceReference());
144

    
145
        //save
146
        getTaxonService().save(taxonBase);
147
        taxonIdMap.put(idCat, taxonBase);
148

    
149
    }
150

    
151

    
152

    
153
    /**
154
     * @param state
155
     * @param secRefStr
156
     * @return
157
     */
158
    private Reference getSecRef(SimpleExcelTaxonImportState<CONFIG> state, String secRefStr, String line) {
159
        Reference result = state.getReference(secRefStr);
160
        if (result == null && secRefStr != null){
161
            result = ReferenceFactory.newBook();
162
            VerbatimTimePeriod tp = TimePeriodParser.parseStringVerbatim(secRefStr.substring(secRefStr.length()-4));
163
            String authorStrPart = secRefStr.substring(0, secRefStr.length()-6);
164
            if (! (authorStrPart + ", " + tp.getYear()).equals(secRefStr)){
165
                logger.warn(line + "Sec ref could not be parsed: " + secRefStr);
166
            }else{
167
                result.setDatePublished(tp);
168
            }
169
            TeamOrPersonBase<?> author = state.getAgentBase(authorStrPart);
170
            if (author == null){
171
                if (authorStrPart.contains("&")){
172
                    Team team = Team.NewInstance();
173
                    String[] authorSplit = authorStrPart.split("&");
174
                    String[] firstAuthorSplit = authorSplit[0].trim().split(",");
175
                    for (String authorStr : firstAuthorSplit){
176
                        addTeamMember(team, authorStr);
177
                    }
178
                    addTeamMember(team, authorSplit[1]);
179
                    result.setAuthorship(team);
180
                    state.putAgentBase(team.getTitleCache(), team);
181
                }else if (authorStrPart.equalsIgnoreCase("Tropicos") || authorStrPart.equalsIgnoreCase("The Plant List")
182
                        || authorStrPart.equalsIgnoreCase("APG IV")){
183
                    result.setTitle(authorStrPart);
184
                }else{
185
                    Person person = Person.NewInstance();
186
                    person.setFamilyName(authorStrPart);
187
                    result.setAuthorship(person);
188
                    state.putAgentBase(person.getTitleCache(), person);
189
                }
190
            }else{
191
                result.setAuthorship(author);
192
            }
193
            state.putReference(secRefStr, result);
194
        }else if(secRefStr == null){
195
            return state.getConfig().getSecReference();
196
        }
197

    
198
        return result;
199
    }
200

    
201

    
202

    
203
    /**
204
     * @param team
205
     * @param author
206
     */
207
    private void addTeamMember(Team team, String author) {
208
        if (StringUtils.isNotBlank(author)){
209
            Person person = Person.NewInstance();
210
            person.setFamilyName(author.trim());
211
            team.addTeamMember(person);
212
        }
213
    }
214

    
215

    
216

    
217
    /**
218
     * @param record
219
     * @param state
220
     * @return
221
     */
222
    private IBotanicalName makeName(String line, Map<String, String> record, SimpleExcelTaxonImportState<CONFIG> state) {
223

    
224
        String authorStr = getValueNd(record, "AutorSinAnio");
225
        String nameStr = getValue(record, "Nombre");
226
        String nomRefStr = getValue(record, "CitaNomenclatural");
227
        String refType = getValue(record, "ReferenceType");
228
        String idCat = getValue(record, "IdCAT");
229
        String rankStr = getValue(record, "CategoriaTaxonomica");
230
        String annotation = getValue(record, "Anotacion al Taxon");
231

    
232
        //rank
233
        Rank rank = null;
234
        try {
235
            rank = state.getTransformer().getRankByKey(rankStr);
236
            if (Rank.SUBSPECIES().equals(rank) || Rank.VARIETY().equals(rank)){
237
                int i = nameStr.lastIndexOf(" ");
238
                nameStr = nameStr.substring(0, i) + " " + rank.getAbbreviation() + nameStr.substring(i);
239
            }
240
        } catch (UndefinedTransformerMethodException e) {
241
            logger.warn(line + "Rank not recognized: " + rankStr);
242
        }
243

    
244
        //name + author
245
        String fullNameStr = nameStr + (authorStr != null ? " " + authorStr : "");
246

    
247
        IBotanicalName fullName = (IBotanicalName)nameParser.parseFullName(fullNameStr, NomenclaturalCode.ICNAFP, rank);
248
        if (fullName.isProtectedTitleCache()){
249
            logger.warn(line + "Name could not be parsed: " + fullNameStr );
250
        }else{
251
            replaceAuthorNamesAndNomRef(state, fullName);
252
        }
253
        IBotanicalName existingName = getExistingName(state, fullName);
254

    
255
        //reference
256
        String refNameStr = getRefNameStr(nomRefStr, refType, fullNameStr);
257

    
258
        IBotanicalName referencedName = (IBotanicalName)nameParser.parseReferencedName(refNameStr, NomenclaturalCode.ICNAFP, rank);
259
        if (referencedName.isProtectedFullTitleCache() || referencedName.isProtectedTitleCache()){
260
            logger.warn(line + "Referenced name could not be parsed: " + refNameStr );
261
        }else{
262
            addSourcesToReferences(referencedName, state);
263
            replaceAuthorNamesAndNomRef(state, referencedName);
264
        }
265
        adaptRefTypeForGeneric(referencedName, refType);
266

    
267
        //compare nom. ref. with Borhidi
268
        IBotanicalName result= referencedName;
269
        Boolean equal = null;
270
        if (existingName != null){
271
            String existingRefTitle = existingName.getFullTitleCache();
272
            String conabioRefTitle = referencedName.getFullTitleCache();
273
            if (!existingRefTitle.equals(conabioRefTitle)){
274
                existingName.setNomenclaturalMicroReference(referencedName.getNomenclaturalMicroReference());
275
                existingName.setNomenclaturalReference(referencedName.getNomenclaturalReference());
276
                equal = false;
277
            }else{
278
                equal = true;
279
            }
280
            result = existingName;
281
        }
282
        addNomRefExtension(state, result, equal);
283

    
284
        //status
285
        if (annotation != null && (annotation.equals("nom. illeg.") || annotation.equals("nom. cons."))){
286
            try {
287
                NomenclaturalStatusType nomStatusType = NomenclaturalStatusType.getNomenclaturalStatusTypeByAbbreviation(annotation, result);
288
                result.addStatus(NomenclaturalStatus.NewInstance(nomStatusType));
289
            } catch (UnknownCdmTypeException e) {
290
                logger.warn(line + "nomStatusType not recognized: " + annotation);
291
            }
292
        }
293

    
294
        this.addOriginalSource(result, idCat, TAXON_NAMESPACE + "_Name", state.getConfig().getSourceReference());
295

    
296
        return result;
297
    }
298

    
299

    
300

    
301
    /**
302
     * @param name
303
     * @param state
304
     */
305
    private void addSourcesToReferences(IBotanicalName name, SimpleExcelTaxonImportState<CONFIG> state) {
306
        Reference nomRef = name.getNomenclaturalReference();
307
        if (nomRef != null){
308
            nomRef.addSource(makeOriginalSource(state));
309
            if (nomRef.getInReference() != null){
310
                nomRef.getInReference().addSource(makeOriginalSource(state));
311
            }
312
        }
313
    }
314

    
315

    
316

    
317
    /**
318
     * @param referencedName
319
     * @param refType
320
     */
321
    private void adaptRefTypeForGeneric(IBotanicalName referencedName, String refTypeStr) {
322
        INomenclaturalReference ref = referencedName.getNomenclaturalReference();
323
        if (ref == null){
324
            return;
325
        }
326
        ReferenceType refType = refTypeByRefTypeStr(refTypeStr);
327
        if (ref.getType() != refType && refType == ReferenceType.Book){
328
            ref.setType(refType);
329
        }
330
    }
331

    
332

    
333
    private ReferenceType refTypeByRefTypeStr(String refType){
334
        if ("A".equals(refType)){  //Article
335
            return ReferenceType.Article;
336
        }else if ("B".equals(refType)){   //Book
337
            return ReferenceType.Book;
338
        }else if (refType == null){   //Book
339
            return null;
340
        }else{
341
            throw new IllegalArgumentException("RefType not supported " + refType);
342
        }
343
    }
344

    
345
    /**
346
     * @param nomRefStr
347
     * @param refType
348
     * @param fullNameStr
349
     * @return
350
     */
351
    private String getRefNameStr(String nomRefStr, String refTypeStr, String fullNameStr) {
352
        String refNameStr = fullNameStr;
353
        ReferenceType refType = refTypeByRefTypeStr(refTypeStr);
354
        if (refType == ReferenceType.Article){
355
            refNameStr = fullNameStr + " in " + nomRefStr;
356
        }else if (refType == ReferenceType.Book){
357
            refNameStr = fullNameStr + ", " + nomRefStr;
358
        }else if (refType == null && nomRefStr != null){
359
            logger.warn("RefType is null but nomRefStr exists");
360
        }
361
        return refNameStr;
362
    }
363

    
364
    /**
365
     * @param state
366
     * @param equal
367
     * @param referencedName
368
     */
369
    private void addNomRefExtension(SimpleExcelTaxonImportState<CONFIG> state, IBotanicalName name, Boolean equal) {
370
        String equalStr = equal == null ? "" : equal == true ? "EQUAL\n" : "NOT EQUAL\n";
371
        name.setFullTitleCache(null, false);
372
        String newExtensionStr = name.getFullTitleCache() + " - CONABIO";
373
        UUID uuidNomRefExtension = MexicoConabioTransformer.uuidNomRefExtension;
374
        for (Extension extension : name.getExtensions()){
375
            if (extension.getType().getUuid().equals(uuidNomRefExtension)){
376
                extension.setValue(equalStr + extension.getValue() + "\n" + newExtensionStr);
377
                return;
378
            }
379
        }
380
        String label = "Nomenclatural reference in Sources";
381
        String abbrev = "Nom. ref. src.";
382
        ExtensionType extensionType = getExtensionType(state, uuidNomRefExtension, label, label, abbrev);
383
        Extension.NewInstance((TaxonName)name, newExtensionStr, extensionType);
384
    }
385

    
386
    boolean nameMapIsInitialized = false;
387
    /**
388
     * @param state
389
     * @param fullName
390
     * @return
391
     */
392
    private IBotanicalName getExistingName(SimpleExcelTaxonImportState<CONFIG> state, IBotanicalName fullName) {
393
        initExistinNames(state);
394
        return (IBotanicalName)state.getName(fullName.getTitleCache());
395
    }
396

    
397
    /**
398
     * @param state
399
     */
400
    @SuppressWarnings("rawtypes")
401
    private void initExistinNames(SimpleExcelTaxonImportState<CONFIG> state) {
402
        if (!nameMapIsInitialized){
403
            List<String> propertyPaths = Arrays.asList("");
404
            List<TaxonName> existingNames = this.getNameService().list(null, null, null, null, propertyPaths);
405
            for (TaxonName tnb : existingNames){
406
                state.putName(tnb.getTitleCache(), tnb);
407
            }
408
            nameMapIsInitialized = true;
409
        }
410
    }
411

    
412

    
413

    
414
    /**
415
     * @param record
416
     * @param string
417
     * @return
418
     */
419
    private String getValueNd(Map<String, String> record, String string) {
420
        String value = getValue(record, string);
421
        if ("ND".equals(value)){
422
            return null;
423
        }else{
424
            return value;
425
        }
426
    }
427

    
428

    
429
    @Override
430
    protected void secondPass(SimpleExcelTaxonImportState<CONFIG> state) {
431
//        IdCAT_AscendenteInmediato, IdCATRel, TipoRelacion
432
        Map<String, String> record = state.getOriginalRecord();
433
        String line = state.getCurrentLine() + ": ";
434

    
435
        String parentStr = getValue(record, "IdCAT_AscendenteInmediato");
436
        String relStr = getValue(record, "IdCATRel");
437

    
438
        String statusStr = getValue(record, "EstatusNombre");
439

    
440
        Classification classification = getClassification(state);
441
        String idCat = getValue(record, "IdCAT");
442
        TaxonBase<?> taxonBase = taxonIdMap.get(idCat);
443
        Taxon parent;
444
        if ("aceptado".equals(statusStr)){
445
            parent = (Taxon)taxonIdMap.get(parentStr);
446
            if (parent == null){
447
                logger.warn(line + "Parent is missing: "+ parentStr);
448
            }else{
449
                Taxon taxon = (Taxon)taxonBase;
450
                Reference relRef = null;  //TODO
451
                classification.addParentChild(parent, taxon, relRef, null);
452
                makeConceptRelation(line, taxon.getName());
453

    
454
            }
455
        }else if (statusStr.startsWith("sin")){
456
            parent = (Taxon)taxonIdMap.get(relStr);
457
            if (parent == null){
458
                logger.warn(line + "Accepted taxon is missing: "+ relStr);
459
            }else{
460
                Synonym synonym = (Synonym)taxonBase;
461
                parent.addSynonym(synonym, SynonymType.SYNONYM_OF());
462
                makeConceptRelation(line, synonym.getName());
463
            }
464
        }
465
    }
466

    
467
     /**
468
     * @param line
469
     * @param name
470
     */
471
    private void makeConceptRelation(String line, TaxonName name) {
472
        if (name.getTaxonBases().size()==2){
473
            Iterator<TaxonBase> it = name.getTaxonBases().iterator();
474
            Taxon taxon1 = getAccepted(it.next());
475
            Taxon taxon2 = getAccepted(it.next());
476
            Reference citation = null;
477
            TaxonRelationship rel;
478
            if (taxon1.getSec().getUuid().equals(MexicoConabioTransformer.uuidReferenceBorhidi)){
479
                rel = taxon1.addTaxonRelation(taxon2, TaxonRelationshipType.CONGRUENT_TO(),
480
                        citation, null);
481
            }else{
482
                rel = taxon2.addTaxonRelation(taxon1, TaxonRelationshipType.CONGRUENT_TO(),
483
                        citation, null);
484
            }
485
            rel.setDoubtful(true);
486
        }else if (name.getTaxonBases().size()>2){
487
            logger.warn(line + "Names with more than 2 taxa not yet handled");
488
        }
489

    
490
    }
491

    
492
    /**
493
     * @param next
494
     * @return
495
     */
496
    private Taxon getAccepted(TaxonBase<?> taxonBase) {
497
        if (taxonBase.isInstanceOf(Taxon.class)){
498
            return CdmBase.deproxy(taxonBase, Taxon.class);
499
        }else{
500
            Synonym syn = CdmBase.deproxy(taxonBase, Synonym.class);
501
            return syn.getAcceptedTaxon();
502
        }
503
    }
504

    
505

    
506

    
507
    /**
508
     * @return
509
     */
510
    private Classification getClassification(SimpleExcelTaxonImportState<CONFIG> state) {
511
        if (classification == null){
512
            MexicoConabioImportConfigurator config = state.getConfig();
513
            classification = Classification.NewInstance(config.getClassificationName());
514
            classification.setUuid(config.getClassificationUuid());
515
            classification.setReference(config.getSecReference());
516
            getClassificationService().save(classification);
517
        }
518
        return classification;
519
    }
520

    
521

    
522
    @Override
523
    protected boolean isIgnore(SimpleExcelTaxonImportState<CONFIG> state) {
524
        return ! state.getConfig().isDoTaxa();
525
    }
526
}
(6-6/9)