|
1 |
// $Id$
|
|
2 |
/**
|
|
3 |
* Copyright (C) 2017 EDIT
|
|
4 |
* European Distributed Institute of Taxonomy
|
|
5 |
* http://www.e-taxonomy.eu
|
|
6 |
*
|
|
7 |
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
|
8 |
* See LICENSE.TXT at the top of this package for the full license terms.
|
|
9 |
*/
|
|
10 |
package eu.etaxonomy.cdm.io.bogota;
|
|
11 |
|
|
12 |
import java.util.HashMap;
|
|
13 |
import java.util.Map;
|
|
14 |
import java.util.UUID;
|
|
15 |
|
|
16 |
import org.apache.log4j.Logger;
|
|
17 |
import org.joda.time.Partial;
|
|
18 |
import org.springframework.stereotype.Component;
|
|
19 |
|
|
20 |
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
|
|
21 |
import eu.etaxonomy.cdm.common.CdmUtils;
|
|
22 |
import eu.etaxonomy.cdm.io.common.utils.ImportDeduplicationHelper;
|
|
23 |
import eu.etaxonomy.cdm.model.agent.AgentBase;
|
|
24 |
import eu.etaxonomy.cdm.model.agent.Institution;
|
|
25 |
import eu.etaxonomy.cdm.model.agent.Person;
|
|
26 |
import eu.etaxonomy.cdm.model.agent.Team;
|
|
27 |
import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
|
|
28 |
import eu.etaxonomy.cdm.model.common.CdmBase;
|
|
29 |
import eu.etaxonomy.cdm.model.common.DefinedTerm;
|
|
30 |
import eu.etaxonomy.cdm.model.common.ExtensionType;
|
|
31 |
import eu.etaxonomy.cdm.model.common.IdentifiableSource;
|
|
32 |
import eu.etaxonomy.cdm.model.common.Language;
|
|
33 |
import eu.etaxonomy.cdm.model.common.TimePeriod;
|
|
34 |
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
|
|
35 |
import eu.etaxonomy.cdm.model.description.TaxonDescription;
|
|
36 |
import eu.etaxonomy.cdm.model.location.Country;
|
|
37 |
import eu.etaxonomy.cdm.model.location.NamedArea;
|
|
38 |
import eu.etaxonomy.cdm.model.location.NamedAreaLevel;
|
|
39 |
import eu.etaxonomy.cdm.model.location.NamedAreaType;
|
|
40 |
import eu.etaxonomy.cdm.model.location.Point;
|
|
41 |
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
|
|
42 |
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
|
|
43 |
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
|
|
44 |
import eu.etaxonomy.cdm.model.name.TaxonName;
|
|
45 |
import eu.etaxonomy.cdm.model.occurrence.Collection;
|
|
46 |
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
|
|
47 |
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
|
|
48 |
import eu.etaxonomy.cdm.model.reference.Reference;
|
|
49 |
import eu.etaxonomy.cdm.model.taxon.Synonym;
|
|
50 |
import eu.etaxonomy.cdm.model.taxon.Taxon;
|
|
51 |
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
|
|
52 |
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
|
|
53 |
import eu.etaxonomy.cdm.strategy.parser.DeterminationModifierParser;
|
|
54 |
import eu.etaxonomy.cdm.strategy.parser.SpecimenTypeParser;
|
|
55 |
import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
|
|
56 |
|
|
57 |
/**
|
|
58 |
* @author a.mueller
|
|
59 |
* @date 21.04.2017
|
|
60 |
*
|
|
61 |
*/
|
|
62 |
@Component
|
|
63 |
public class BogotaSpecimenImport<CONFIG extends BogotaSpecimenImportConfigurator>
|
|
64 |
extends SimpleExcelSpecimenImport<CONFIG> {
|
|
65 |
|
|
66 |
private static final long serialVersionUID = -884838817884874228L;
|
|
67 |
private static final Logger logger = Logger.getLogger(BogotaSpecimenImport.class);
|
|
68 |
|
|
69 |
private static final String COL_TAXON_UUID = "Platform Name ID = cdmID";
|
|
70 |
private static final String COL_VOUCHER_ID = "Voucher ID";
|
|
71 |
|
|
72 |
private static final String COL_FAMILY = "Family";
|
|
73 |
private static final String COL_GENUS = "Genus";
|
|
74 |
private static final String COL_SPECIFIC_EPI = "Specific Epithet";
|
|
75 |
private static final String COL_BASIONYM_AUTHOR = "Author in parenthesis";
|
|
76 |
private static final String COL_AUTHOR = "Author";
|
|
77 |
private static final String COL_IDENTIFIER = "Identifier";
|
|
78 |
private static final String COL_IDENTIFICATION_DATE = "Identification date";
|
|
79 |
private static final String COL_IDENTIFICATION_QUALIFIER = "Qualifier";
|
|
80 |
private static final String COL_TYPUS = "Type";
|
|
81 |
private static final String COL_IDENTIFICATION_HISTORY = "Identification history";
|
|
82 |
private static final String COL_COLLECTOR_VERBATIM = "Verbatim Collectors (Originalfeld JBB)";
|
|
83 |
private static final String COL_COLLECTOR_LASTNAME = "Primary Collector Last Name (Originalfeld JBB)";
|
|
84 |
private static final String COL_COLLECTOR_FIRSTNAME = "Primary Collector First Name Initial (Originalfeld JBB)";
|
|
85 |
private static final String COL_COLLECTOR_MIDDLENAME = "Primary Collector Middle Name Initial (Originalfeld JBB)";
|
|
86 |
private static final String COL_COLLECTOR_TYPE = "Primary collector type (Originalfeld JBB)";
|
|
87 |
private static final String COL_COLLECTOR_NUMBER = "Collector's No";
|
|
88 |
private static final String COL_COLLECTORS = "Collectors";
|
|
89 |
private static final String COL_COLLECTION_DATE_FROM = "Collection Date from";
|
|
90 |
private static final String COL_COLLECTION_DATE_TO = "Collection Date to";
|
|
91 |
private static final String COL_ALTITUDE_FROM = "Altitude Value from";
|
|
92 |
private static final String COL_ALTITUDE_TO = "Altitude Value to";
|
|
93 |
private static final String COL_ALTITUDE_UNIT = "Altitude Unit";
|
|
94 |
private static final String COL_LOCALITY = "Locality";
|
|
95 |
private static final String COL_LOCALITY_ID = "LocalityID";
|
|
96 |
private static final String COL_LATITUDE = "Latitude";
|
|
97 |
private static final String COL_LONGITUDE = "Longitude";
|
|
98 |
private static final String COL_ERROR_DISTANCE = "Error distance in m";
|
|
99 |
private static final String COL_COUNTRY = "Country";
|
|
100 |
private static final String COL_STATE_AREA = "State/Province/Greater Area";
|
|
101 |
private static final String COL_GEO_METHOD = "Geocode Method";
|
|
102 |
private static final String COL_HABITUS = "Habitus";
|
|
103 |
private static final String COL_COLLECTION = "[Series] Voucher location";
|
|
104 |
|
|
105 |
private static final UUID uuidAnonymous = UUID.fromString("2303f043-6e92-4afa-9082-7719e78a1c8a");
|
|
106 |
private static final UUID uuidBogota = UUID.fromString("95b6cb03-8452-4439-98bd-8c1aa3c1da4e");
|
|
107 |
private static final UUID uuidDefaultGeocodMethod = UUID.fromString("0983e680-b0ca-4e46-8df7-0f1d757a2e01");
|
|
108 |
private static final UUID uuidExtTypeIdentificationHistory = UUID.fromString("7cee5c29-e16b-4e6f-ad57-bf7044259375");
|
|
109 |
private static final UUID uuidDetQualVelAff = UUID.fromString("511a0c23-2646-4035-b570-36bdc2eb5557");
|
|
110 |
|
|
111 |
// @SuppressWarnings("unchecked")
|
|
112 |
private ImportDeduplicationHelper<SimpleExcelSpecimenImportState<?>> deduplicationHelper;
|
|
113 |
// = (ImportDeduplicationHelper<SimpleExcelSpecimenImportState<?>>)ImportDeduplicationHelper.NewStandaloneInstance();
|
|
114 |
|
|
115 |
|
|
116 |
@Override
|
|
117 |
protected String getWorksheetName() {
|
|
118 |
return "To be imported";
|
|
119 |
}
|
|
120 |
|
|
121 |
// private boolean isFirst = true;
|
|
122 |
// private TransactionStatus tx = null;
|
|
123 |
|
|
124 |
/**
|
|
125 |
* {@inheritDoc}
|
|
126 |
*/
|
|
127 |
@Override
|
|
128 |
protected void firstPass(SimpleExcelSpecimenImportState<CONFIG> state) {
|
|
129 |
// if (isFirst){
|
|
130 |
// tx = this.startTransaction();
|
|
131 |
// isFirst = false;
|
|
132 |
// }
|
|
133 |
|
|
134 |
HashMap<String, String> record = state.getOriginalRecord();
|
|
135 |
|
|
136 |
String voucherId = getValue(record, COL_VOUCHER_ID);
|
|
137 |
if (!isInInterval(state)){
|
|
138 |
return;
|
|
139 |
}
|
|
140 |
String line = state.getCurrentLine() + " (id:"+ voucherId+"): ";
|
|
141 |
if (state.getCurrentLine() % 100 == 0){System.out.println(line);}
|
|
142 |
try {
|
|
143 |
|
|
144 |
//species
|
|
145 |
TaxonBase<?> taxonBase = getOrCreateTaxon(state, line, record, voucherId);
|
|
146 |
|
|
147 |
if (taxonBase != null){
|
|
148 |
Taxon taxon = getTaxon(taxonBase);
|
|
149 |
|
|
150 |
TaxonDescription taxonDescription = getTaxonDescription(state, line, taxon);
|
|
151 |
|
|
152 |
DerivedUnit specimen = makeSpecimen(state, line, record, voucherId, taxonBase);
|
|
153 |
|
|
154 |
IndividualsAssociation indAssoc = IndividualsAssociation.NewInstance(specimen);
|
|
155 |
indAssoc.addImportSource(voucherId, COL_VOUCHER_ID, getSourceCitation(state), null);
|
|
156 |
taxonDescription.addElement(indAssoc);
|
|
157 |
|
|
158 |
}
|
|
159 |
} catch (Exception e) {
|
|
160 |
state.getResult().addError("An unexpected exception appeared in record", e, null, line);
|
|
161 |
e.printStackTrace();
|
|
162 |
}
|
|
163 |
|
|
164 |
}
|
|
165 |
|
|
166 |
|
|
167 |
/**
|
|
168 |
* @param state
|
|
169 |
* @return
|
|
170 |
*/
|
|
171 |
private boolean isInInterval(SimpleExcelSpecimenImportState<CONFIG> state) {
|
|
172 |
Integer min = state.getConfig().getMinLineNumber();
|
|
173 |
Integer max = state.getConfig().getMaxLineNumber();
|
|
174 |
Integer current = state.getCurrentLine();
|
|
175 |
if (current < min || current > max){
|
|
176 |
return false;
|
|
177 |
}else{
|
|
178 |
return true;
|
|
179 |
}
|
|
180 |
}
|
|
181 |
|
|
182 |
|
|
183 |
/**
|
|
184 |
* @param state
|
|
185 |
* @param line
|
|
186 |
* @param taxon
|
|
187 |
* @return
|
|
188 |
*/
|
|
189 |
private TaxonDescription getTaxonDescription(SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
190 |
Taxon taxon) {
|
|
191 |
Reference ref = getSourceCitation(state);
|
|
192 |
TaxonDescription desc = this.getTaxonDescription(taxon, ref, ! IMAGE_GALLERY, CREATE);
|
|
193 |
return desc;
|
|
194 |
}
|
|
195 |
|
|
196 |
|
|
197 |
/**
|
|
198 |
* @param state
|
|
199 |
* @param line
|
|
200 |
* @param record
|
|
201 |
* @param voucherId
|
|
202 |
* @return
|
|
203 |
*/
|
|
204 |
private DerivedUnit makeSpecimen(SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
205 |
HashMap<String, String> record, String voucherId, TaxonBase<?> taxonBase) {
|
|
206 |
|
|
207 |
DerivedUnitFacade facade = DerivedUnitFacade.NewPreservedSpecimenInstance();
|
|
208 |
facade.setAccessionNumber(voucherId);
|
|
209 |
makeDetermination(facade.innerDerivedUnit(), state, line, record, taxonBase.getName());
|
|
210 |
makeTypus(facade.innerDerivedUnit(), state, line, record, taxonBase.getName());
|
|
211 |
makeCollectorFields(facade, state, line, record);
|
|
212 |
makeLocationFields(facade, state, line, record);
|
|
213 |
makeHabitus(facade, state, line, record);
|
|
214 |
makeCollection(facade, state, line, record);
|
|
215 |
DerivedUnit specimen = facade.innerDerivedUnit();
|
|
216 |
specimen.addSource(makeOriginalSource(state));
|
|
217 |
return specimen;
|
|
218 |
}
|
|
219 |
|
|
220 |
|
|
221 |
/**
|
|
222 |
* @param innerDerivedUnit
|
|
223 |
* @param state
|
|
224 |
* @param line
|
|
225 |
* @param record
|
|
226 |
* @param name
|
|
227 |
*/
|
|
228 |
private void makeTypus(DerivedUnit specimen, SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
229 |
HashMap<String, String> record, TaxonName name) {
|
|
230 |
String typus = record.get(COL_TYPUS);
|
|
231 |
if (typus != null){
|
|
232 |
SpecimenTypeDesignationStatus status;
|
|
233 |
try {
|
|
234 |
status = SpecimenTypeParser.parseSpecimenTypeStatus(typus);
|
|
235 |
SpecimenTypeDesignation designation = SpecimenTypeDesignation.NewInstance();
|
|
236 |
designation.setTypeStatus(status);
|
|
237 |
name.addSpecimenTypeDesignation(specimen, status, null, null, null, false, false);
|
|
238 |
} catch (UnknownCdmTypeException e) {
|
|
239 |
state.getResult().addWarning("Type designation could not be parsed", null, line);
|
|
240 |
}
|
|
241 |
}
|
|
242 |
}
|
|
243 |
|
|
244 |
|
|
245 |
/**
|
|
246 |
* @param facade
|
|
247 |
* @param state
|
|
248 |
* @param line
|
|
249 |
* @param record
|
|
250 |
*/
|
|
251 |
private void makeCollection(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state,
|
|
252 |
String line, HashMap<String, String> record) {
|
|
253 |
String strCollection = record.get(COL_COLLECTION);
|
|
254 |
String collectionFormat = ".*\\([A-Z]{2,4}\\)";
|
|
255 |
if (!strCollection.matches(collectionFormat)){
|
|
256 |
String message = "Voucher location format does not match the expected format. Voucher '(" + strCollection + ")' location not added.";
|
|
257 |
state.getResult().addError(message, null, line);
|
|
258 |
return;
|
|
259 |
}
|
|
260 |
String[] splits = strCollection.split("\\(");
|
|
261 |
String collectionName = splits[0];
|
|
262 |
String collectionCode = splits[1].replace(")", "");
|
|
263 |
Collection collection = Collection.NewInstance();
|
|
264 |
collection.setName(collectionName);
|
|
265 |
collection.setCode(collectionCode);
|
|
266 |
collection = getDeduplicationHelper(state).getExistingCollection(state, collection);
|
|
267 |
facade.setCollection(collection);
|
|
268 |
}
|
|
269 |
|
|
270 |
|
|
271 |
/**
|
|
272 |
* @param state
|
|
273 |
* @return
|
|
274 |
*/
|
|
275 |
private ImportDeduplicationHelper<SimpleExcelSpecimenImportState<?>> getDeduplicationHelper(SimpleExcelSpecimenImportState<CONFIG> state) {
|
|
276 |
if (deduplicationHelper == null){
|
|
277 |
deduplicationHelper = ImportDeduplicationHelper.NewInstance(this, state);
|
|
278 |
}
|
|
279 |
return deduplicationHelper;
|
|
280 |
}
|
|
281 |
|
|
282 |
|
|
283 |
/**
|
|
284 |
* @param facade
|
|
285 |
* @param state
|
|
286 |
* @param line
|
|
287 |
* @param record
|
|
288 |
*/
|
|
289 |
private void makeHabitus(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
290 |
HashMap<String, String> record) {
|
|
291 |
String habitus = record.get(COL_HABITUS);
|
|
292 |
if (habitus != null){
|
|
293 |
facade.setPlantDescription(habitus);
|
|
294 |
}
|
|
295 |
}
|
|
296 |
|
|
297 |
|
|
298 |
/**
|
|
299 |
* @param facade
|
|
300 |
* @param state
|
|
301 |
* @param line
|
|
302 |
* @param record
|
|
303 |
* @param voucherId
|
|
304 |
*/
|
|
305 |
private void makeLocationFields(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
306 |
HashMap<String, String> record) {
|
|
307 |
//Altitude
|
|
308 |
String strAltitudeFrom = record.get(COL_ALTITUDE_FROM);
|
|
309 |
String strAltitudeTo = record.get(COL_ALTITUDE_TO);
|
|
310 |
Integer intAltitudeFrom = intFromString(state, strAltitudeFrom, line, COL_ALTITUDE_FROM);
|
|
311 |
Integer intAltitudeTo = intFromString(state, strAltitudeTo, line, COL_ALTITUDE_TO);
|
|
312 |
if (intAltitudeFrom != null){
|
|
313 |
facade.setAbsoluteElevation(intAltitudeFrom);
|
|
314 |
if (!intAltitudeFrom.equals(intAltitudeTo)){
|
|
315 |
facade.setAbsoluteElevationMax(intAltitudeTo);
|
|
316 |
}
|
|
317 |
if (!record.get(COL_ALTITUDE_UNIT).equals("m")){
|
|
318 |
state.getResult().addWarning("Altitude unit is not m but " + record.get(COL_ALTITUDE_UNIT), "makeLocationFields", line);
|
|
319 |
}
|
|
320 |
}
|
|
321 |
checkNoToIfNoFrom(strAltitudeFrom, strAltitudeTo, state, line, COL_ALTITUDE_TO);
|
|
322 |
|
|
323 |
//locality
|
|
324 |
String locality = record.get(COL_LOCALITY);
|
|
325 |
if (locality != null){ //should always exist
|
|
326 |
facade.setLocality(locality, Language.SPANISH_CASTILIAN());
|
|
327 |
}
|
|
328 |
|
|
329 |
//Lat + Long
|
|
330 |
String strLatitude = record.get(COL_LATITUDE);
|
|
331 |
String strLongitude = record.get(COL_LONGITUDE);
|
|
332 |
String strError = record.get(COL_ERROR_DISTANCE);
|
|
333 |
Double dblLatitude = doubleFromString(state, strLatitude, line, COL_LATITUDE);
|
|
334 |
Double dblLongitude = doubleFromString(state, strLongitude, line, COL_LONGITUDE);
|
|
335 |
Integer intError = intFromString(state, strError, line, COL_ERROR_DISTANCE);
|
|
336 |
ReferenceSystem referenceSystem = makeReferenceSystem(state, record, line);
|
|
337 |
|
|
338 |
if (dblLatitude != null || dblLongitude != null || intError != null){ //should always exist
|
|
339 |
Point exactLocation = Point.NewInstance(dblLongitude, dblLatitude, referenceSystem, intError);
|
|
340 |
facade.setExactLocation(exactLocation);
|
|
341 |
}
|
|
342 |
|
|
343 |
//Country
|
|
344 |
String strCountry = record.get(COL_COUNTRY);
|
|
345 |
if (strCountry != null){
|
|
346 |
if (strCountry.equals("Colombia")){
|
|
347 |
Country colombia = Country.COLOMBIAREPUBLICOF();
|
|
348 |
colombia.setLabel("Colombia");
|
|
349 |
getTermService().saveOrUpdate(colombia);
|
|
350 |
facade.setCountry(colombia);
|
|
351 |
}else{
|
|
352 |
state.getResult().addWarning("Country was not Colombia as expected but " + strCountry,
|
|
353 |
"makeLocationFields", line);
|
|
354 |
}
|
|
355 |
}
|
|
356 |
|
|
357 |
//State
|
|
358 |
String strStateArea = record.get(COL_STATE_AREA);
|
|
359 |
if (strStateArea != null){
|
|
360 |
if (strStateArea.replaceAll("\\s", "").equalsIgnoreCase("Bogotá,D.C.")){
|
|
361 |
NamedArea bogota = makeBogota(state, line);
|
|
362 |
facade.addCollectingArea(bogota);
|
|
363 |
}else{
|
|
364 |
state.getResult().addWarning(COL_STATE_AREA + " was not 'Bogotá, D.C.' as expected but " + strCountry,
|
|
365 |
"makeLocationFields", line);
|
|
366 |
}
|
|
367 |
}
|
|
368 |
}
|
|
369 |
|
|
370 |
|
|
371 |
/**
|
|
372 |
* @param strAltitudeFrom
|
|
373 |
* @param strAltitudeTo
|
|
374 |
* @param state
|
|
375 |
* @param line
|
|
376 |
* @param colAltitudeTo
|
|
377 |
*/
|
|
378 |
private void checkNoToIfNoFrom(String strFrom, String strTo,
|
|
379 |
SimpleExcelSpecimenImportState<CONFIG> state,
|
|
380 |
String line, String toAttributeName) {
|
|
381 |
if (isNotBlank(strTo) && isBlank(strFrom)){
|
|
382 |
String message = "A min-max attribute has a max value (%s) but no min value. This is invalid."
|
|
383 |
+ " The max value attribute name is %s.";
|
|
384 |
message = String.format(message, strTo, toAttributeName);
|
|
385 |
state.getResult().addWarning(message, null, line);
|
|
386 |
}
|
|
387 |
}
|
|
388 |
|
|
389 |
private ReferenceSystem defaultGeocodeMethod;
|
|
390 |
|
|
391 |
/**
|
|
392 |
* @param state
|
|
393 |
* @param record
|
|
394 |
* @param line
|
|
395 |
* @return
|
|
396 |
*/
|
|
397 |
private ReferenceSystem makeReferenceSystem(SimpleExcelSpecimenImportState<CONFIG> state,
|
|
398 |
Map<String, String> record, String line) {
|
|
399 |
String defaultStrRefSys = "Wieczorek, J., Guo, Q., & Hijmans, R. (2004). The point-radius method for georeferencing locality descriptions and calculating associated uncertainty. International journal of geographical information science, 18(8), 745-767.; Escobar D, DÃaz SR, Jojoa LM, Rudas E, AlbarracÃn RD, RamÃrez C, Gómez JY, López CR, Saavedra J (2015). Georreferenciación de localidades: Una guÃa de referencia para colecciones biológicas. Instituto de Investigación de Recursos Biológicos Alexander von Humboldt – Instituto de Ciencias Naturales, Universidad Nacional de Colombia. Bogotá D.C., Colombia. 95 p.";
|
|
400 |
String strRefSys = record.get(COL_GEO_METHOD);
|
|
401 |
if (strRefSys == null){
|
|
402 |
return null;
|
|
403 |
}else if (!strRefSys.equals(defaultStrRefSys)){
|
|
404 |
state.getResult().addError("The expected Geocode Method is not the expected default method. Geocode Method was not added.", null, line);
|
|
405 |
return null;
|
|
406 |
}else if (defaultGeocodeMethod != null){
|
|
407 |
return defaultGeocodeMethod;
|
|
408 |
}else{
|
|
409 |
String label = "Point radius method";
|
|
410 |
String description = defaultStrRefSys;
|
|
411 |
String labelAbbrev = "PRM";
|
|
412 |
defaultGeocodeMethod = getReferenceSystem(state, uuidDefaultGeocodMethod,
|
|
413 |
label, description, labelAbbrev, null);
|
|
414 |
return defaultGeocodeMethod;
|
|
415 |
}
|
|
416 |
}
|
|
417 |
|
|
418 |
private NamedArea bogota;
|
|
419 |
/**
|
|
420 |
* @param state
|
|
421 |
* @param line
|
|
422 |
* @return
|
|
423 |
*/
|
|
424 |
private NamedArea makeBogota(SimpleExcelSpecimenImportState<CONFIG> state, String line) {
|
|
425 |
if (bogota != null){
|
|
426 |
return bogota;
|
|
427 |
}else{
|
|
428 |
String label = "Bogotá, D.C.";
|
|
429 |
NamedAreaType areaType = NamedAreaType.ADMINISTRATION_AREA();
|
|
430 |
NamedAreaLevel level = NamedAreaLevel.STATE();
|
|
431 |
bogota = getNamedArea(state, uuidBogota, label, label, null, areaType,
|
|
432 |
level, null, null, null);
|
|
433 |
return bogota;
|
|
434 |
}
|
|
435 |
}
|
|
436 |
|
|
437 |
|
|
438 |
/**
|
|
439 |
* @param facade
|
|
440 |
* @param state
|
|
441 |
* @param line
|
|
442 |
* @param record
|
|
443 |
*/
|
|
444 |
private void makeCollectorFields(DerivedUnitFacade facade, SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
445 |
HashMap<String, String> record) {
|
|
446 |
|
|
447 |
//collector number
|
|
448 |
facade.setFieldNumber(record.get(COL_COLLECTOR_NUMBER));
|
|
449 |
|
|
450 |
//gathering date
|
|
451 |
String dateFrom = unknownToNull((record.get(COL_COLLECTION_DATE_FROM)));
|
|
452 |
String dateTo = unknownToNull(record.get(COL_COLLECTION_DATE_TO));
|
|
453 |
checkNoToIfNoFrom(dateFrom, dateTo, state, line, COL_COLLECTION_DATE_TO);
|
|
454 |
try {
|
|
455 |
if (dateFrom != null && dateFrom.equals(dateTo)){
|
|
456 |
dateTo = null;
|
|
457 |
}
|
|
458 |
TimePeriod gatheringPeriod = TimePeriodParser.parseEnglishDate(dateFrom, dateTo);
|
|
459 |
facade.setGatheringPeriod(gatheringPeriod);
|
|
460 |
} catch (Exception e) {
|
|
461 |
state.getResult().addError("Error creating gathering date", e, null, line);
|
|
462 |
}
|
|
463 |
|
|
464 |
//collector
|
|
465 |
String collectorType = record.get(COL_COLLECTOR_TYPE);
|
|
466 |
String collectors = record.get(COL_COLLECTORS);
|
|
467 |
AgentBase<?> collector;
|
|
468 |
if (collectorType.startsWith("Anonymous")){
|
|
469 |
collector = getAnonymous();
|
|
470 |
}else if (collectorType.equals("Brother") || collectorType.equals("Person")){
|
|
471 |
Person person = Person.NewInstance();
|
|
472 |
if (collectorType.equals("Person")){
|
|
473 |
person.setLastname(record.get(COL_COLLECTOR_LASTNAME));
|
|
474 |
String initials = CdmUtils.concat("", record.get(COL_COLLECTOR_FIRSTNAME), record.get(COL_COLLECTOR_MIDDLENAME));
|
|
475 |
initials = (initials == null)? null : initials.replaceAll("\\s", "");
|
|
476 |
person.setInitials(initials);
|
|
477 |
String full = person.getTitleCache();
|
|
478 |
if (!full.equals(collectors)){
|
|
479 |
person.setTitleCache(collectors, true);
|
|
480 |
//TODO longterm, collector cache
|
|
481 |
}
|
|
482 |
}else{
|
|
483 |
person.setTitleCache(collectors, true);
|
|
484 |
person.setPrefix("Hno.");
|
|
485 |
person.setFirstname(collectors.replace("Hno.", "").trim());
|
|
486 |
}
|
|
487 |
collector = person;
|
|
488 |
}else if (collectorType.equals("Group")){
|
|
489 |
collector = Team.NewTitledInstance(collectors, collectors);
|
|
490 |
}else if (collectorType.equals("Institution")){
|
|
491 |
collector = Institution.NewNamedInstance(collectors);
|
|
492 |
}else{
|
|
493 |
String message = "Collector type " + collectorType + " not yet supported by import. Collector not added.";
|
|
494 |
state.getResult().addError(message, null, line);
|
|
495 |
collector = null;
|
|
496 |
}
|
|
497 |
collector = getDeduplicationHelper(state).getExistingAgent(state, collector);
|
|
498 |
facade.setCollector(collector);
|
|
499 |
}
|
|
500 |
|
|
501 |
|
|
502 |
/**
|
|
503 |
* @param string
|
|
504 |
* @return
|
|
505 |
*/
|
|
506 |
private String unknownToNull(String string) {
|
|
507 |
if (string == null || string.equalsIgnoreCase("unknown")){
|
|
508 |
return null;
|
|
509 |
}else{
|
|
510 |
return string;
|
|
511 |
}
|
|
512 |
}
|
|
513 |
|
|
514 |
private Person anonymous;
|
|
515 |
private Person getAnonymous() {
|
|
516 |
if (anonymous != null){
|
|
517 |
return anonymous;
|
|
518 |
}
|
|
519 |
anonymous = CdmBase.deproxy(getAgentService().find(uuidAnonymous), Person.class);
|
|
520 |
if (anonymous == null){
|
|
521 |
anonymous = Person.NewTitledInstance("Anon.");
|
|
522 |
anonymous.setUuid(uuidAnonymous);
|
|
523 |
getAgentService().save(anonymous);
|
|
524 |
}
|
|
525 |
return anonymous;
|
|
526 |
}
|
|
527 |
|
|
528 |
|
|
529 |
/**
|
|
530 |
* @param facade
|
|
531 |
* @param state
|
|
532 |
* @param line
|
|
533 |
* @param record
|
|
534 |
* @param taxonBase
|
|
535 |
*/
|
|
536 |
private void makeDetermination(DerivedUnit specimen, SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
537 |
HashMap<String, String> record, TaxonName taxonName) {
|
|
538 |
|
|
539 |
DeterminationEvent determination;
|
|
540 |
determination = DeterminationEvent.NewInstance(taxonName, specimen);
|
|
541 |
determination.setPreferredFlag(true);
|
|
542 |
|
|
543 |
//determiner/identifier
|
|
544 |
TeamOrPersonBase<?> determiner = makeDeterminer(state, record, line);
|
|
545 |
determination.setDeterminer(determiner);
|
|
546 |
|
|
547 |
//date
|
|
548 |
TimePeriod date = makeIdentificationDate(state, record, line);
|
|
549 |
determination.setTimeperiod(date);
|
|
550 |
|
|
551 |
//qualifier
|
|
552 |
DefinedTerm qualifier = makeDeterminationQualifier(state, record, line);
|
|
553 |
determination.setModifier(qualifier);
|
|
554 |
|
|
555 |
//history
|
|
556 |
String history = record.get(COL_IDENTIFICATION_HISTORY);
|
|
557 |
if (history != null){
|
|
558 |
String label = "Identification History";
|
|
559 |
String text = label;
|
|
560 |
ExtensionType detHistoryType = getExtensionType(state, uuidExtTypeIdentificationHistory, label, text, null);
|
|
561 |
specimen.addExtension(history, detHistoryType);
|
|
562 |
}
|
|
563 |
}
|
|
564 |
|
|
565 |
|
|
566 |
/**
|
|
567 |
* @param state
|
|
568 |
* @param record
|
|
569 |
* @param line
|
|
570 |
* @return
|
|
571 |
*/
|
|
572 |
private TeamOrPersonBase<?> makeDeterminer(SimpleExcelSpecimenImportState<CONFIG> state,
|
|
573 |
HashMap<String, String> record, String line) {
|
|
574 |
String identifier = record.get(COL_IDENTIFIER);
|
|
575 |
if (identifier == null){
|
|
576 |
return null;
|
|
577 |
}else if (identifier.equals("Anon.")){
|
|
578 |
return getAnonymous();
|
|
579 |
}else{
|
|
580 |
Person person = Person.NewInstance();
|
|
581 |
person.setTitleCache(identifier, true);
|
|
582 |
// String format = "([A-Z]\\.){1,3}" +
|
|
583 |
// NonViralNameParserImplRegExBase.capitalWord +
|
|
584 |
// "(-" + NonViralNameParserImplRegExBase.capitalWord;
|
|
585 |
|
|
586 |
String[] splits = identifier.split("\\.");
|
|
587 |
int length = splits.length;
|
|
588 |
if (splits[length - 1].equals("")){
|
|
589 |
splits[length - 2]= splits[length - 2]+".";
|
|
590 |
length--;
|
|
591 |
}
|
|
592 |
if (splits[length - 1].startsWith("-")){
|
|
593 |
splits[length - 2]= splits[length - 2]+"." + splits[length - 1];
|
|
594 |
length--;
|
|
595 |
}
|
|
596 |
String lastName = splits[length - 1];
|
|
597 |
String initials = null;
|
|
598 |
for (int i= 0; i < length-1;i++){
|
|
599 |
initials = CdmUtils.concat("", initials, splits[i]+".");
|
|
600 |
}
|
|
601 |
person.setLastname(lastName);
|
|
602 |
person.setInitials(initials);
|
|
603 |
TeamOrPersonBase<?> result = getDeduplicationHelper(state).getExistingAuthor(state, person);
|
|
604 |
return result;
|
|
605 |
}
|
|
606 |
}
|
|
607 |
|
|
608 |
|
|
609 |
/**
|
|
610 |
* @param state
|
|
611 |
* @param record
|
|
612 |
* @param line
|
|
613 |
* @return
|
|
614 |
*/
|
|
615 |
private TimePeriod makeIdentificationDate(SimpleExcelSpecimenImportState<CONFIG> state,
|
|
616 |
HashMap<String, String> record, String line) {
|
|
617 |
String strDate = record.get(COL_IDENTIFICATION_DATE);
|
|
618 |
if (strDate == null || strDate.equals("s.n.")){
|
|
619 |
return null;
|
|
620 |
}
|
|
621 |
String[] splits = strDate.split("/");
|
|
622 |
String strYear = splits[splits.length-1];
|
|
623 |
String strMonth = splits.length < 2? null:splits[splits.length-2];
|
|
624 |
String strDay = splits.length < 3? null:splits[splits.length-3];
|
|
625 |
|
|
626 |
Integer year = intFromString(state, strYear, line, COL_IDENTIFICATION_DATE);
|
|
627 |
Integer month = intFromString(state, strMonth, line, COL_IDENTIFICATION_DATE);
|
|
628 |
Integer day = intFromString(state, strDay, line, COL_IDENTIFICATION_DATE);
|
|
629 |
Partial start = TimePeriodParser.makePartialFromDateParts(year, month, day);
|
|
630 |
return TimePeriod.NewInstance(start);
|
|
631 |
}
|
|
632 |
|
|
633 |
|
|
634 |
/**
|
|
635 |
* @param state
|
|
636 |
* @param record
|
|
637 |
* @param line
|
|
638 |
* @return
|
|
639 |
*/
|
|
640 |
private DefinedTerm makeDeterminationQualifier(SimpleExcelSpecimenImportState<CONFIG> state,
|
|
641 |
HashMap<String, String> record, String line) {
|
|
642 |
String qualifier = record.get(COL_IDENTIFICATION_QUALIFIER);
|
|
643 |
if (qualifier != null){
|
|
644 |
try {
|
|
645 |
return DeterminationModifierParser.parseDeterminationQualifier(qualifier);
|
|
646 |
} catch (UnknownCdmTypeException e) {
|
|
647 |
//TODO add to terms
|
|
648 |
if (qualifier.equals("vel. aff.")){
|
|
649 |
|
|
650 |
DefinedTerm velAff = (DefinedTerm)getTermService().find(uuidDetQualVelAff);
|
|
651 |
if (velAff == null){
|
|
652 |
velAff = DefinedTerm.NewModifierInstance(qualifier, qualifier, qualifier);
|
|
653 |
velAff.setUuid(uuidDetQualVelAff);
|
|
654 |
getTermService().save(velAff);
|
|
655 |
}
|
|
656 |
return velAff;
|
|
657 |
}
|
|
658 |
state.getResult().addError("Determination qualifier could not be recognized: " + qualifier, null, line);
|
|
659 |
return null;
|
|
660 |
}
|
|
661 |
}else{
|
|
662 |
return null;
|
|
663 |
}
|
|
664 |
}
|
|
665 |
|
|
666 |
|
|
667 |
/**
|
|
668 |
* @param taxonBase
|
|
669 |
* @return
|
|
670 |
*/
|
|
671 |
private Taxon getTaxon(TaxonBase<?> taxonBase) {
|
|
672 |
if (taxonBase.isInstanceOf(Synonym.class)){
|
|
673 |
return CdmBase.deproxy(taxonBase, Synonym.class).getAcceptedTaxon();
|
|
674 |
}else{
|
|
675 |
return CdmBase.deproxy(taxonBase, Taxon.class);
|
|
676 |
}
|
|
677 |
}
|
|
678 |
|
|
679 |
|
|
680 |
/**
|
|
681 |
* @param state
|
|
682 |
* @param line
|
|
683 |
* @param record
|
|
684 |
* @param noStr
|
|
685 |
* @return
|
|
686 |
*/
|
|
687 |
private TaxonBase<?> getOrCreateTaxon(SimpleExcelSpecimenImportState<CONFIG> state, String line,
|
|
688 |
HashMap<String, String> record, String noStr) {
|
|
689 |
|
|
690 |
String strUuidTaxon = record.get(COL_TAXON_UUID);
|
|
691 |
if (strUuidTaxon != null){
|
|
692 |
UUID uuidTaxon;
|
|
693 |
try {
|
|
694 |
uuidTaxon = UUID.fromString(strUuidTaxon);
|
|
695 |
} catch (Exception e) {
|
|
696 |
state.getResult().addError("Taxon uuid has incorrect format. Taxon could not be loaded. Data not imported.", null, line);
|
|
697 |
return null;
|
|
698 |
}
|
|
699 |
TaxonBase<?> result = getTaxonService().find(uuidTaxon);
|
|
700 |
if (result == null){
|
|
701 |
state.getResult().addError("Taxon for uuid "+strUuidTaxon+" could not be found in database. "
|
|
702 |
+ "Taxon could not be loaded. Data not imported.", null, line);
|
|
703 |
|
|
704 |
}
|
|
705 |
return result;
|
|
706 |
}else{
|
|
707 |
TaxonName taxonName = null;
|
|
708 |
Reference sec = null;
|
|
709 |
Taxon result = Taxon.NewInstance(taxonName, sec);
|
|
710 |
result.addSource(makeOriginalSource(state));
|
|
711 |
//TODO export uuid
|
|
712 |
|
|
713 |
// state.getResult().addInfo("Taxon");
|
|
714 |
//TODO
|
|
715 |
return null;
|
|
716 |
}
|
|
717 |
}
|
|
718 |
|
|
719 |
|
|
720 |
@Override
|
|
721 |
protected void secondPass(SimpleExcelSpecimenImportState<CONFIG> state) {
|
|
722 |
// if (tx != null){
|
|
723 |
// this.commitTransaction(tx);
|
|
724 |
// tx = null;
|
|
725 |
// }
|
|
726 |
}
|
|
727 |
|
|
728 |
@Override
|
|
729 |
protected IdentifiableSource makeOriginalSource(SimpleExcelSpecimenImportState<CONFIG> state) {
|
|
730 |
return IdentifiableSource.NewDataImportInstance(getValue(state.getOriginalRecord(), COL_VOUCHER_ID), COL_VOUCHER_ID, getSourceCitation(state));
|
|
731 |
}
|
|
732 |
|
|
733 |
/**
|
|
734 |
* @param state
|
|
735 |
* @return
|
|
736 |
*/
|
|
737 |
protected Reference getSourceCitation(SimpleExcelSpecimenImportState<CONFIG> state) {
|
|
738 |
Reference source = state.getConfig().getSourceReference();
|
|
739 |
if (source.getId() == 0){
|
|
740 |
Reference persisted = getReferenceService().find(source.getUuid());
|
|
741 |
if (persisted == null){
|
|
742 |
getReferenceService().saveOrUpdate(source);
|
|
743 |
}else{
|
|
744 |
state.getConfig().setSourceReference(persisted);
|
|
745 |
source = persisted;
|
|
746 |
}
|
|
747 |
}
|
|
748 |
return source;
|
|
749 |
}
|
|
750 |
}
|
ref #6903 first implementation of Bogota specimen import, not yet with taxon import for missing taxa