Project

General

Profile

Download (21.9 KB) Statistics
| Branch: | 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.salvador;
10

    
11
import java.text.ParseException;
12
import java.util.HashMap;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.Set;
16
import java.util.UUID;
17
import java.util.regex.Matcher;
18
import java.util.regex.Pattern;
19

    
20
import org.apache.commons.lang3.StringUtils;
21
import org.joda.time.DateTime;
22
import org.joda.time.format.DateTimeFormat;
23
import org.joda.time.format.DateTimeFormatter;
24
import org.springframework.stereotype.Component;
25

    
26
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
27
import eu.etaxonomy.cdm.common.URI;
28
import eu.etaxonomy.cdm.io.csv.in.CsvImportBase;
29
import eu.etaxonomy.cdm.model.agent.Person;
30
import eu.etaxonomy.cdm.model.agent.Team;
31
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
32
import eu.etaxonomy.cdm.model.common.Annotation;
33
import eu.etaxonomy.cdm.model.common.CdmBase;
34
import eu.etaxonomy.cdm.model.common.ExtensionType;
35
import eu.etaxonomy.cdm.model.common.Language;
36
import eu.etaxonomy.cdm.model.common.TimePeriod;
37
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
38
import eu.etaxonomy.cdm.model.description.Feature;
39
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
40
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
41
import eu.etaxonomy.cdm.model.description.TaxonDescription;
42
import eu.etaxonomy.cdm.model.description.TextData;
43
import eu.etaxonomy.cdm.model.location.Country;
44
import eu.etaxonomy.cdm.model.location.NamedArea;
45
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
46
import eu.etaxonomy.cdm.model.occurrence.Collection;
47
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
48
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
49
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
50
import eu.etaxonomy.cdm.model.taxon.Taxon;
51
import eu.etaxonomy.cdm.model.term.TermType;
52
import eu.etaxonomy.cdm.model.term.TermVocabulary;
53

    
54
/**
55
 * @author a.mueller
56
 * @since 08.07.2017
57
 *
58
 */
59
@Component
60
public class SalvadorSpecimenImport
61
            extends CsvImportBase<SalvadorSpecimenImportConfigurator,SalvadorSpecimenImportState, FieldUnit> {
62

    
63
    private static final long serialVersionUID = -2165916187195347780L;
64

    
65
    @Override
66
    protected void handleSingleLine(SalvadorSpecimenImportState state) {
67

    
68
        try {
69
            UUID factUuid = UUID.fromString(state.getCurrentRecord().get("specimenFactUuid"));
70

    
71
            if (existingFieldUnits.get(factUuid)== null){
72

    
73
                FieldUnit fieldUnit = makeFieldUnit(state);
74
                DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(
75
                        SpecimenOrObservationType.PreservedSpecimen, fieldUnit);
76
                makeFieldUnitData(state, facade);
77
                makeSpecimen(state, facade);
78
            }else{
79
                FieldUnit fieldUnit = fieldUnitMap.get(factUuid);
80
                if (fieldUnit == null){
81
                    fieldUnit = CdmBase.deproxy(getOccurrenceService().find(existingFieldUnits.get(factUuid)), FieldUnit.class);
82
                    fieldUnitMap.put(factUuid, fieldUnit);
83
                }
84
                DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(
85
                        SpecimenOrObservationType.PreservedSpecimen, fieldUnit);
86
                makeSpecimenDuplicate(state, facade);
87
            }
88

    
89
            return;
90
        } catch (Exception e) {
91
            String message = "Unexpected error in handleSingleLine: " + e.getMessage();
92
            state.getResult().addException(e, message, null, String.valueOf(state.getRow()));
93
            e.printStackTrace();
94
        }
95
    }
96

    
97
    private void makeSpecimenDuplicate(SalvadorSpecimenImportState state,
98
            DerivedUnitFacade facade) {
99

    
100
        Map<String, String> record = state.getCurrentRecord();
101

    
102
        TaxonDescription desc = getTaxonDescription(state, record);
103

    
104
        int row = state.getRow();
105
        String herbariaStr = record.get("Herbaria");
106
        String[] splits = herbariaStr.split(";");
107
        for (String split : splits){
108
            if ("B".equals(split)){
109
                Collection collection = getCollection(split, row);
110
                facade.setCollection(collection);
111
                if (record.get("B-Barcode") != null){
112
                    facade.setBarcode(record.get("B-Barcode"));
113
                }
114
                String uriStr = record.get("B_UUID");
115
                if (uriStr != null){
116
                    URI uri = URI.create(uriStr);
117
                    facade.setPreferredStableUri(uri);
118
                }
119
                IndividualsAssociation assoc = IndividualsAssociation.NewInstance(facade.innerDerivedUnit());
120
                assoc.setFeature(Feature.SPECIMEN());
121
                desc.addElement(assoc);
122
            }
123

    
124
        }
125
    }
126

    
127

    
128
    private Map<UUID, FieldUnit> fieldUnitMap = new HashMap<>();
129
    private Map<UUID, UUID> existingFieldUnits = new HashMap<>();
130
    private FieldUnit makeFieldUnit(SalvadorSpecimenImportState state) {
131

    
132
        Map<String, String> record = state.getCurrentRecord();
133
        UUID factUuid = UUID.fromString(record.get("specimenFactUuid"));
134

    
135
        TextData textSpecimen = (TextData)getDescriptionElementService().find(factUuid);
136
        textSpecimen.setFeature(getTexSpecimenFeature());
137

    
138
        FieldUnit fieldUnit = FieldUnit.NewInstance();
139

    
140
        fieldUnitMap.put(factUuid, fieldUnit);
141
        existingFieldUnits.put(factUuid, fieldUnit.getUuid());
142

    
143
        return fieldUnit;
144
    }
145

    
146
    //taxonUuid, TaxonDescription map
147
    private Map<UUID, TaxonDescription> taxonDescMap = new HashMap<>();
148
    //taxonUuid, TaxonDescription.uuid map
149
    private Map<UUID, UUID> existingTaxonDescs = new HashMap<>();
150

    
151
    private TaxonDescription getTaxonDescription(SalvadorSpecimenImportState state,
152
            Map<String, String> record) {
153

    
154
        int row = state.getRow();
155
        UUID taxonUuid = UUID.fromString(record.get("taxonUuid"));
156
        TaxonDescription taxonDesc = taxonDescMap.get(taxonUuid);
157
        if (taxonDesc == null && existingTaxonDescs.get(taxonUuid) != null){
158
            taxonDesc = (TaxonDescription)getDescriptionService().find(existingTaxonDescs.get(taxonUuid));
159
            taxonDescMap.put(taxonUuid, taxonDesc);
160
        }
161
        if (taxonDesc == null){
162

    
163
            Taxon taxon = (Taxon)getTaxonService().find(taxonUuid);
164

    
165
            taxonDesc = TaxonDescription.NewInstance(taxon);
166
            taxonDesc.setTitleCache("JACQ import for " + taxon.getName().getTitleCache(), true);
167
            taxonDesc.addImportSource(null, null, state.getConfig().getSourceReference(), String.valueOf(row));
168
            taxonDescMap.put(taxonUuid, taxonDesc);
169
            existingTaxonDescs.put(taxonUuid, taxonDesc.getUuid());
170
        }else{
171
            System.out.println("Reuse desc: " + row);
172
        }
173

    
174
        return taxonDesc;
175
    }
176

    
177
    /**
178
     * @param config
179
     * @param facade
180
     * @param importResult
181
     */
182
    private void makeSpecimen(SalvadorSpecimenImportState state, DerivedUnitFacade facade) {
183

    
184
        Map<String, String> record = state.getCurrentRecord();
185

    
186
        TaxonDescription desc = getTaxonDescription(state, record);
187

    
188
        int row = state.getRow();
189
        String herbariaStr = record.get("Herbaria");
190
        String laguUuidStr = record.get("LAGU_UUID");
191
        if (laguUuidStr != null && !herbariaStr.contains("LAGU")){
192
            herbariaStr += ";LAGU";
193
        }
194
        String[] splits = herbariaStr.split(";");
195
        boolean isFirst = true;
196
        for (String split : splits){
197
            Collection collection = getCollection(split, row);
198
            DerivedUnit unit;
199
            if (isFirst){
200
                facade.setCollection(collection);
201
                unit = facade.innerDerivedUnit();
202
            }else{
203
                unit = facade.addDuplicate(collection, null, null, null, null);
204
            }
205
            isFirst = false;
206
            if ("B".equalsIgnoreCase(split)){
207
                unit.setBarcode(record.get("B-Barcode"));
208
                String uriStr = record.get("B_UUID");
209
                if (uriStr != null){
210
                    URI uri = URI.create(uriStr);
211
                    unit.setPreferredStableUri(uri);
212
                }
213
            }else if ("LAGU".equalsIgnoreCase(split)){
214
                String uriStr = record.get("LAGU_UUID");
215
                if (uriStr != null){
216
                    URI uri = URI.create(uriStr);
217
                    unit.setPreferredStableUri(uri);
218
                }
219
            }
220

    
221
            IndividualsAssociation assoc = IndividualsAssociation.NewInstance(unit);
222
            assoc.setFeature(Feature.SPECIMEN());
223
            desc.addElement(assoc);
224
        }
225
    }
226

    
227
    private Map<String, Collection> collectionMap = new HashMap<>();
228

    
229
    private Collection getCollection(String code, int row) {
230

    
231
        if (StringUtils.isBlank(code)){
232
            return null;
233
        }
234
        if (collectionMap.isEmpty()){
235
            List<Collection> collections = getCollectionService().list(null, null, null, null, null);
236
            for (Collection collection :collections){
237
                collectionMap.put(collection.getCode(), collection);
238
            }
239
        }
240
        if (collectionMap.get(code) == null){
241
            Collection collection = Collection.NewInstance();
242
            collection.setCode(code);
243
            collectionMap.put(code, collection);
244
            getCollectionService().save(collection);
245
        }
246
        return collectionMap.get(code);
247
    }
248

    
249
    private void makeFieldUnitData(SalvadorSpecimenImportState state, DerivedUnitFacade facade) {
250

    
251
        Map<String, String> record = state.getCurrentRecord();
252
        int row = state.getRow();
253

    
254
        Language spanish = Language.SPANISH_CASTILIAN();
255

    
256
        //idInSource
257
        String idInSource = record.get("IdInSource");
258
        String nameSpace = "http://resolv.jacq.org/";
259
        facade.innerFieldUnit().addImportSource(idInSource, nameSpace,
260
                state.getConfig().getSourceReference(), String.valueOf(row));
261

    
262
        //collector
263
        TeamOrPersonBase<?> collector = makeCollectorTeam(state, record, row);
264
        if (collector != null){
265
            collector = state.getDeduplicationHelper().getExistingAuthor(collector);
266
            facade.setCollector(collector);
267
        }
268

    
269
        //collectorsNumber
270
        facade.setFieldNumber(record.get("CollectorsNumber"));
271

    
272
        //CollectionDate
273
        String collectionDate = record.get("CollectionDate");
274
        if (collectionDate != null){
275
            TimePeriod tp;
276
            if (collectionDate.equals("1987")){
277
                tp = TimePeriod.NewInstance(1987);
278
                state.getResult().addWarning("Only year is not correct: " + collectionDate, state.getRow());
279
            }else{
280
                DateTimeFormatter f = DateTimeFormat.forPattern("yyyy-MM-dd");
281
                collectionDate = collectionDate.replace(" 00:00:00", "");
282
                DateTime dateTime = f.parseDateTime(collectionDate);
283
                tp = TimePeriod.NewInstance(dateTime, null);
284
            }
285
            facade.getGatheringEvent(true).setTimeperiod(tp);
286
        }
287
        //Country
288
        Country country = makeCountry(state, record, row);
289
        facade.setCountry(country);
290

    
291
        //Area_Major
292
        NamedArea area = makeMajorArea(state);
293
        if(area != null){
294
            facade.addCollectingArea(area);
295
        }
296

    
297
        //Locality
298
        String locality = record.get("Locality");
299
        if (locality != null){
300
            facade.setLocality(locality, spanish);
301
        }
302

    
303
        //Geo
304
        String latitude = record.get("LatitudeDecimal");
305
        String longitude = record.get("LongitudeDecimal");
306
        longitude = normalizeLongitude(longitude);
307
        if (latitude != null || longitude != null){
308
            if (latitude == null || longitude == null){
309
                state.getResult().addError("Only Lat or Long is null", row);
310
            }
311
            if (!"WGS84".equals(record.get("ReferenceSystem"))){
312
                state.getResult().addWarning("Reference system is not WGS84", row);
313
            }
314
            String errorRadiusStr =record.get("ErrorRadius");
315
            Integer errorRadius = null;
316
            if (errorRadiusStr != null){
317
                errorRadius = Integer.valueOf(errorRadiusStr);
318
            }
319
            try {
320
                facade.setExactLocationByParsing(longitude, latitude, ReferenceSystem.WGS84(), errorRadius);
321
            } catch (ParseException e) {
322
                state.getResult().addError("Error when parsing exact location" + e.getMessage(), row);
323
            }
324
        }
325

    
326
        //Altitude
327
        String altStr = record.get("Altitude");
328
        if (altStr != null){
329
            facade.setAbsoluteElevation(Integer.valueOf(altStr));
330
        }
331
        String altStrMax = record.get("AltitudeMax");
332
        if (altStrMax != null){
333
            facade.setAbsoluteElevationMax(Integer.valueOf(altStrMax));
334
        }
335

    
336
        //habitat
337
        String habitatStr = record.get("habitat");
338
        if (habitatStr != null){
339
            //TODO habitat, not ecology
340
            facade.setEcology(habitatStr, spanish);
341
//            //habitat
342
//            TextData habitat = TextData.NewInstance(Feature.HABITAT(), habitatStr, spanish, null);
343
//            facade.innerFieldUnit().getDescriptions().iterator().next()
344
//                .addElement(habitat);
345
//            facade.removeEcology(spanish);
346
        }
347

    
348
        //plant description
349
        String plantDescription = record.get("PlantDescription");
350
        if (plantDescription != null){
351
            facade.setPlantDescription(plantDescription, spanish);
352
        }
353

    
354
        //note
355
        //TODO is this field unit??
356
        String note = record.get("note");
357
        if (note != null){
358
            facade.innerFieldUnit().addAnnotation(Annotation.NewInstance(note, spanish));
359
        }
360

    
361
        //IdentificationHistory
362
        String identificationHistory = record.get("IdentificationHistory");
363
        if (identificationHistory != null){
364
            ExtensionType type = getExtensionType();
365
            facade.innerFieldUnit().addExtension(identificationHistory, type);
366
        }
367

    
368
        //LocalCommonName
369
        String localCommonName = record.get("LocalCommonName");
370
        if (localCommonName != null){
371
            CommonTaxonName commonName = CommonTaxonName.NewInstance(localCommonName, spanish);
372
            Set<SpecimenDescription> descs = (Set)facade.innerFieldUnit().getDescriptions();
373
            if (descs.isEmpty()){
374
                SpecimenDescription desc = SpecimenDescription.NewInstance(facade.innerFieldUnit());
375
                descs.add(desc);
376
            }
377
            descs.iterator().next().addElement(commonName);
378
        }
379

    
380
    }
381

    
382

    
383
    /**
384
     * @param longitude
385
     * @return
386
     */
387
    private String normalizeLongitude(String longitude) {
388
        if (longitude == null || longitude.startsWith("-")){
389
            return longitude;
390
        }else{
391
            return "-" + longitude;
392
        }
393
    }
394

    
395

    
396
    private ExtensionType identificationHistoryType;
397

    
398
    /**
399
     * @return
400
     */
401
    private ExtensionType getExtensionType() {
402
        if (identificationHistoryType == null){
403
            identificationHistoryType = ExtensionType.NewInstance("Identification History", "Identification History", null);
404
            UUID vocUuid = uuidUserDefinedExtensionTypeVocabulary;
405
            TermVocabulary<ExtensionType> voc = getVocabularyService().find(vocUuid);
406
            if (voc == null){
407
                voc = TermVocabulary.NewInstance(TermType.ExtensionType, ExtensionType.class,
408
                        "User defined extension types", "User defined extension types", null, null);
409
                getVocabularyService().save(voc);
410
            }
411
            voc.addTerm(identificationHistoryType);
412
            getTermService().saveOrUpdate(identificationHistoryType);
413
        }
414
        return identificationHistoryType;
415
    }
416

    
417

    
418

    
419
    private Feature textSpecimenFeature;
420

    
421

    
422
    private Feature getTexSpecimenFeature() {
423
        if (textSpecimenFeature == null){
424
            UUID uuidSpecimenTextOld = SalvadorImportTransformer.uuidSalvadorTextSpecimenOldFeature;
425
            textSpecimenFeature = (Feature)getTermService().find(uuidSpecimenTextOld);
426
        }
427
        if (textSpecimenFeature == null){
428
            String label = "Text Specimen";
429
            textSpecimenFeature = Feature.NewInstance(label, label, null);
430
            UUID vocUuid = SalvadorImportTransformer.uuidSalvadorFeatureVoc;
431
            TermVocabulary<Feature> voc = getVocabularyService().find(vocUuid);
432
            if (voc == null){
433
                voc = TermVocabulary.NewInstance(TermType.Feature, Feature.class,
434
                        "User defined features", "User defined features", null, null);
435
                getVocabularyService().save(voc);
436
            }
437
            textSpecimenFeature.setUuid(SalvadorImportTransformer.uuidSalvadorTextSpecimenOldFeature);
438
            voc.addTerm(textSpecimenFeature);
439
            getTermService().saveOrUpdate(textSpecimenFeature);
440
        }
441
        return textSpecimenFeature;
442
    }
443

    
444

    
445
    private Map<String, NamedArea> majorAreaMap = null;
446

    
447
    /**
448
     * @param state
449
     * @param record
450
     * @param row
451
     * @return
452
     */
453
    private NamedArea makeMajorArea(SalvadorSpecimenImportState state) {
454

    
455
        if (majorAreaMap == null){
456
            majorAreaMap = new HashMap<>();
457
            TermVocabulary<NamedArea> voc = getVocabularyService().find(UUID.fromString("8ef90ca3-77d7-4adc-8bbc-1eb354e61b65"));
458
            for (NamedArea area : voc.getTerms()){
459
                majorAreaMap.put(area.getTitleCache(), area);
460
            }
461
        }
462

    
463
        String areaStr = state.getCurrentRecord().get("Area_Major");
464
        NamedArea area = majorAreaMap.get(areaStr);
465
        if (area == null && areaStr != null){
466
            state.getResult().addError("Major area not found: " + areaStr, state.getRow());
467
        }
468
        return area;
469
    }
470

    
471
    /**
472
     * @param state
473
     * @param record
474
     * @param i
475
     * @return
476
     */
477
    private Country makeCountry(SalvadorSpecimenImportState state, Map<String, String> record, int row) {
478
        String iso = record.get("IsoCountry");
479
        String countryStr = record.get("COUNTRY");
480
        if (iso == null && countryStr == null){
481
            return null;
482
        }else if ("SLV".equals(iso) && "El Salvador".equals(countryStr)){
483
            return Country.ELSALVADORREPUBLICOF();
484
        }else if ("HND".equals(iso) && "Honduras".equals(countryStr)){
485
            return Country.HONDURASREPUBLICOF();
486
        }else if ("GTM".equals(iso) && "Guatemala".equals(countryStr)){
487
            return Country.GUATEMALAREPUBLICOF();
488
        }else{
489
            String message = "Iso-country combination not recognized: " + iso + " - " + countryStr;
490
            state.getResult().addWarning(message, row);
491
            return null;
492
        }
493
    }
494

    
495
    /**
496
     * @param state
497
     * @param record
498
     * @param row
499
     * @param importResult
500
     * @return
501
     */
502
    private TeamOrPersonBase<?> makeCollectorTeam(SalvadorSpecimenImportState state, Map<String, String> record, int row) {
503

    
504
        Team team = Team.NewInstance();
505
        String first = record.get("COLLECTOR_0");
506
        if(first != null && first.startsWith("Grupo Ecológico")){
507
            team.setTitleCache(first, true);
508
            return team;
509
        }else{
510
            makeCollector(state, 0, team, record, row);
511
            makeCollector(state, 1, team, record, row);
512
            makeCollector(state, 2, team, record, row);
513
            makeCollector(state, 3, team, record, row);
514
            makeCollector(state, 4, team, record, row);
515
            if (team.getTeamMembers().size() == 0){
516
                return null;
517
            }else if (team.getTeamMembers().size() == 1){
518
                return team.getTeamMembers().get(0);
519
            }else{
520
                return team;
521
            }
522
        }
523
    }
524

    
525
    private void makeCollector(SalvadorSpecimenImportState state,
526
            int collectorNo, Team team, Map<String, String> record, int row) {
527

    
528
        String str = record.get("COLLECTOR_" + collectorNo);
529
        if (str == null){
530
            return;
531
        }else{
532
            parsePerson(state, str, team, row);
533
        }
534
        return ;
535
    }
536

    
537
    /**
538
     * @param str
539
     * @param team
540
     * @param row
541
     * @param importResult
542
     */
543
    private void parsePerson(SalvadorSpecimenImportState state, String str, Team team, int row) {
544
        Person result = Person.NewInstance();
545
        String regEx = "(.*),(([A-Z]\\.)+(\\sde)?)";
546
        Pattern pattern = Pattern.compile(regEx);
547
        Matcher matcher = pattern.matcher(str);
548

    
549
        String noInitials = "(Campo|Chinchilla|Campos|Claus|Desconocido|Fomtg|Huezo|Martínez|"
550
                + "Quezada|Romero|Ruíz|Sandoval|Serrano|Vásquez|Cabrera|Calderón)";
551

    
552
        if (matcher.matches()){
553
            String familyname = matcher.group(1);
554
            result.setFamilyName(familyname);
555
            String initials = matcher.group(2);
556
            result.setInitials(initials);
557
        }else if (str.matches(noInitials)){
558
            result.setFamilyName(str);
559
        }else if (str.matches("Martínez, F. de M.")){
560
            result.setFamilyName("Martínez");
561
            result.setInitials("F. de M.");
562
        }else if (str.equals("et al.")){
563
            team.setHasMoreMembers(true);
564
            return;
565
        }else if (str.startsWith("Grupo Ecológico")){
566
            result.setFamilyName(str);
567
        }else{
568
            String message = "Collector did not match pattern: " + str;
569
            state.getResult().addWarning(message, row);
570
            result.setTitleCache(str, true);
571
        }
572
        result = state.getDeduplicationHelper().getExistingAuthor(result);
573

    
574
        team.addTeamMember(result);
575
        return ;
576
    }
577

    
578

    
579
    @Override
580
    protected void refreshTransactionStatus(SalvadorSpecimenImportState state) {
581
        super.refreshTransactionStatus(state);
582
        collectionMap = new HashMap<>();
583
        fieldUnitMap = new HashMap<>();
584
        taxonDescMap = new HashMap<>();
585
        state.getDeduplicationHelper().restartSession(this, state.getResult());
586
    }
587

    
588

    
589

    
590
}
(2-2/4)