Project

General

Profile

Download (20.5 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.net.URI;
12
import java.text.ParseException;
13
import java.util.HashMap;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Set;
17
import java.util.UUID;
18
import java.util.regex.Matcher;
19
import java.util.regex.Pattern;
20

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

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

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

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

    
66
    private ImportDeduplicationHelper<?> dedupHelper;
67

    
68
    /**
69
     * {@inheritDoc}
70
     */
71
    @Override
72
    protected void handleSingleLine(SalvadorSpecimenImportState state) {
73

    
74
        initDedupHelper();
75
        try {
76
            UUID factUuid = UUID.fromString(state.getCurrentRecord().get("specimenFactUuid"));
77
            if (existingFieldUnits.get(factUuid)== null){
78
                FieldUnit fieldUnit = getFieldUnit(state);
79
                DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(
80
                        SpecimenOrObservationType.PreservedSpecimen, fieldUnit);
81
                makeFieldUnitData(state, facade);
82
                makeSpecimen(state, facade);
83
            }else{
84
                FieldUnit fieldUnit = fieldUnitMap.get(factUuid);
85
                if (fieldUnit == null){
86
                    fieldUnit = CdmBase.deproxy(getOccurrenceService().find(existingFieldUnits.get(factUuid)), FieldUnit.class);
87
                    fieldUnitMap.put(factUuid, fieldUnit);
88
                }
89
                DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(
90
                        SpecimenOrObservationType.PreservedSpecimen, fieldUnit);
91
                makeSpecimenDuplicate(state, facade);
92
            }
93

    
94
            return;
95
        } catch (Exception e) {
96
            String message = "Unexpected error in handleSingleLine: " + e.getMessage();
97
            state.getResult().addException(e, message, null, String.valueOf(state.getRow()));
98
            e.printStackTrace();
99
        }
100
    }
101

    
102

    
103
    /**
104
     *
105
     */
106
    private void initDedupHelper() {
107
        if (dedupHelper == null){
108
            dedupHelper = ImportDeduplicationHelper.NewStandaloneInstance();
109
        }
110
    }
111

    
112

    
113
    /**
114
     * @param config
115
     * @param facade
116
     * @param importResult
117
     */
118
    private void makeSpecimenDuplicate(SalvadorSpecimenImportState state,
119
            DerivedUnitFacade facade) {
120
        Map<String, String> record = state.getCurrentRecord();
121
        int row = state.getRow();
122
        String herbariaStr = record.get("Herbaria");
123
        String[] splits = herbariaStr.split(";");
124
        for (String split : splits){
125
            if ("B".equals(split)){
126
                Collection collection = getCollection(split, row);
127
                facade.setCollection(collection);
128
                if (record.get("B-Barcode") != null){
129
                    facade.setBarcode(record.get("B-Barcode"));
130
                }
131
                String uriStr = record.get("B_UUID");
132
                if (uriStr != null){
133
                    URI uri = URI.create(uriStr);
134
                    facade.setPreferredStableUri(uri);
135
                }
136
            }
137
        }
138
    }
139

    
140

    
141
    private Map<UUID, FieldUnit> fieldUnitMap = new HashMap<>();
142
    private Map<UUID, UUID> existingFieldUnits = new HashMap<>();
143
    private FieldUnit getFieldUnit(SalvadorSpecimenImportState state) {
144

    
145
        Map<String, String> record = state.getCurrentRecord();
146
        int row = state.getRow();
147
        UUID factUuid = UUID.fromString(record.get("specimenFactUuid"));
148

    
149
        TextData textSpecimen = (TextData)getDescriptionService().getDescriptionElementByUuid(factUuid);
150
        textSpecimen.setFeature(getTexSpecimenFeature());
151

    
152
        TaxonDescription desc = getTaxonDescription(state, textSpecimen, record, row);
153
        FieldUnit fieldUnit = FieldUnit.NewInstance();
154
        IndividualsAssociation assoc = IndividualsAssociation.NewInstance(fieldUnit);
155
        assoc.setFeature(Feature.SPECIMEN());
156
        desc.addElement(assoc);
157
        fieldUnitMap.put(factUuid, fieldUnit);
158
        existingFieldUnits.put(factUuid, fieldUnit.getUuid());
159

    
160
        return fieldUnit;
161
    }
162

    
163
    private Map<UUID, TaxonDescription> taxonDescMap = new HashMap<>();
164
    private Map<UUID, UUID> existingTaxonDescs = new HashMap<>();
165

    
166
    private TaxonDescription getTaxonDescription(SalvadorSpecimenImportState state,
167
            TextData textSpecimen, Map<String, String> record, int row) {
168
        UUID taxonUuid = UUID.fromString(record.get("taxonUuid"));
169
        TaxonDescription taxonDesc = taxonDescMap.get(taxonUuid);
170
        if (taxonDesc == null && existingTaxonDescs.get(taxonUuid) != null){
171
            taxonDesc = (TaxonDescription)getDescriptionService().find(existingTaxonDescs.get(taxonUuid));
172
            taxonDescMap.put(taxonUuid, taxonDesc);
173
        }
174
        if (taxonDesc == null){
175
            Taxon taxon = CdmBase.deproxy(textSpecimen.getInDescription(),
176
                    TaxonDescription.class).getTaxon();
177
            taxonDesc = TaxonDescription.NewInstance(taxon);
178
            taxonDesc.setTitleCache("JACQ import for " + taxon.getName().getTitleCache(), true);
179
            taxonDesc.addImportSource(null, null, state.getConfig().getSourceReference(), String.valueOf(row));
180
            taxonDescMap.put(taxonUuid, taxonDesc);
181
            existingTaxonDescs.put(taxonUuid, taxonDesc.getUuid());
182
        }else{
183
            System.out.println("Reuse desc: " + row);
184
        }
185

    
186
        return taxonDesc;
187
    }
188

    
189
    /**
190
     * @param config
191
     * @param facade
192
     * @param importResult
193
     */
194
    private void makeSpecimen(SalvadorSpecimenImportState state, DerivedUnitFacade facade) {
195

    
196
        Map<String, String> record = state.getCurrentRecord();
197
        int row = state.getRow();
198
        String herbariaStr = record.get("Herbaria");
199
        String laguUuidStr = record.get("LAGU_UUID");
200
        if (laguUuidStr != null && !herbariaStr.contains("LAGU")){
201
            herbariaStr += ";LAGU";
202
        }
203
        String[] splits = herbariaStr.split(";");
204
        boolean isFirst = true;
205
        for (String split : splits){
206
            Collection collection = getCollection(split, row);
207
            DerivedUnit unit;
208
            if (isFirst){
209
                facade.setCollection(collection);
210
                unit = facade.innerDerivedUnit();
211
            }else{
212
                unit = facade.addDuplicate(collection, null, null, null, null);
213
            }
214
            isFirst = false;
215
            if ("B".equalsIgnoreCase(split)){
216
                unit.setBarcode(record.get("B-Barcode"));
217
                String uriStr = record.get("B_UUID");
218
                if (uriStr != null){
219
                    URI uri = URI.create(uriStr);
220
                    unit.setPreferredStableUri(uri);
221
                }
222
            }else if ("LAGU".equalsIgnoreCase(split)){
223
                String uriStr = record.get("LAGU_UUID");
224
                if (uriStr != null){
225
                    URI uri = URI.create(uriStr);
226
                    unit.setPreferredStableUri(uri);
227
                }
228
            }
229
        }
230
    }
231

    
232
    private Map<String, Collection> collectionMap = new HashMap<>();
233

    
234
    private Collection getCollection(String code, int row) {
235

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

    
254
    /**
255
     * @param config
256
     * @param facade
257
     * @param importResult
258
     */
259
    private void makeFieldUnitData(SalvadorSpecimenImportState state, DerivedUnitFacade facade) {
260

    
261
        Map<String, String> record = state.getCurrentRecord();
262
        int row = state.getRow();
263

    
264
        Language spanish = Language.SPANISH_CASTILIAN();
265

    
266
        //idInSource
267
        String idInSource = record.get("IdInSource");
268
        String nameSpace = "http://resolv.jacq.org/";
269
        facade.innerFieldUnit().addImportSource(idInSource, nameSpace,
270
                state.getConfig().getSourceReference(), String.valueOf(row));
271

    
272
        //collector
273
        TeamOrPersonBase<?> collector = makeCollectorTeam(state, record, row);
274
        if (collector != null){
275
            collector = dedupHelper.getExistingAuthor(null, collector);
276
            facade.setCollector(collector);
277
        }
278

    
279
        //collectorsNumber
280
        facade.setFieldNumber(record.get("CollectorsNumber"));
281

    
282
        //CollectionDate
283
        String collectionDate = record.get("CollectionDate");
284
        if (collectionDate != null){
285
            DateTimeFormatter f = DateTimeFormat.forPattern("yyyy-MM-dd");
286
            collectionDate = collectionDate.replace(" 00:00:00", "");
287
            DateTime dateTime = f.parseDateTime(collectionDate);
288
            TimePeriod tp = TimePeriod.NewInstance(dateTime, null);
289
            facade.getGatheringEvent(true).setTimeperiod(tp);
290
        }
291
        //Country
292
        Country country = makeCountry(state, record, row);
293
        facade.setCountry(country);
294

    
295
        //Area_Major
296
        NamedArea area = makeMajorArea(state);
297
        if(area != null){
298
            facade.addCollectingArea(area);
299
        }
300

    
301
        //Locality
302
        String locality = record.get("Locality");
303
        if (locality != null){
304
            facade.setLocality(locality, spanish);
305
        }
306

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

    
330
        //Altitude
331
        String altStr = record.get("Altitude");
332
        if (altStr != null){
333
            facade.setAbsoluteElevation(Integer.valueOf(altStr));
334
        }
335
        String altStrMax = record.get("AltitudeMax");
336
        if (altStrMax != null){
337
            facade.setAbsoluteElevationMax(Integer.valueOf(altStrMax));
338
        }
339

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

    
352
        //plant description
353
        String plantDescription = record.get("PlantDescription");
354
        if (plantDescription != null){
355
            facade.setPlantDescription(plantDescription, spanish);
356
        }
357

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

    
365
        //IdentificationHistory
366
        String identificationHistory = record.get("IdentificationHistory");
367
        if (identificationHistory != null){
368
            ExtensionType type = getExtensionType();
369
            facade.innerFieldUnit().addExtension(identificationHistory, type);
370
        }
371

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

    
384
    }
385

    
386

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

    
399

    
400
    private ExtensionType identificationHistoryType;
401

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

    
421

    
422

    
423
    private Feature textSpecimenFeature;
424

    
425

    
426
    private Feature getTexSpecimenFeature() {
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,
434
                        "User defined features", "User defined features", null, null);
435
                getVocabularyService().save(voc);
436
            }
437
            voc.addTerm(textSpecimenFeature);
438
            getTermService().saveOrUpdate(textSpecimenFeature);
439
        }
440
        return textSpecimenFeature;
441
    }
442

    
443

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

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

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

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

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

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

    
503
        Team team = Team.NewInstance();
504
        makeCollector(state, 0, team, record, row);
505
        makeCollector(state, 1, team, record, row);
506
        makeCollector(state, 2, team, record, row);
507
        makeCollector(state, 3, team, record, row);
508
        if (team.getTeamMembers().size() == 0){
509
            return null;
510
        }else if (team.getTeamMembers().size() == 1){
511
            return team.getTeamMembers().get(0);
512
        }else{
513
            return team;
514
        }
515
    }
516

    
517
    private void makeCollector(SalvadorSpecimenImportState state,
518
            int collectorNo, Team team, Map<String, String> record, int row) {
519

    
520
        String str = record.get("COLLECTOR_" + collectorNo);
521
        if (str == null){
522
            return;
523
        }else{
524
            Person person = parsePerson(state, str, row);
525
            team.addTeamMember(person);
526
        }
527
        return ;
528
    }
529

    
530
    /**
531
     * @param str
532
     * @param row
533
     * @param importResult
534
     */
535
    private Person parsePerson(SalvadorSpecimenImportState state, String str, int row) {
536
        Person result = Person.NewInstance();
537
        String regEx = "(.*),([A-Z]\\.)+";
538
        Pattern pattern = Pattern.compile(regEx);
539
        Matcher matcher = pattern.matcher(str);
540

    
541

    
542
        if (matcher.matches()){
543
            String lastname = matcher.group(1);
544
            result.setLastname(lastname);
545
            String initials = matcher.group(2);
546
            result.setInitials(initials);
547
        }else{
548
            String message = "Collector did not match pattern: " + str;
549
            state.getResult().addWarning(message, row);
550
            result.setTitleCache(str, true);
551
        }
552
        result = (Person)dedupHelper.getExistingAuthor(null, result);
553

    
554
        return result;
555
    }
556

    
557

    
558
    @Override
559
    protected void refreshTransactionStatus(SalvadorSpecimenImportState state) {
560
        collectionMap = new HashMap<>();
561
        fieldUnitMap = new HashMap<>();
562
        taxonDescMap = new HashMap<>();
563
        dedupHelper.restartSession(this, state.getResult());
564
    }
565

    
566

    
567

    
568
}
(2-2/4)