ref #6369 adapt existing occurrences of interface to removed generics in cdmlib-app
[cdmlib-apps.git] / cdm-eflora / src / main / java / eu / etaxonomy / cdm / io / eflora / centralAfrica / ferns / CentralAfricaFernsTaxonImport.java
1 /**
2 * Copyright (C) 2007 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
10 package eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns;
11
12 import java.sql.ResultSet;
13 import java.sql.SQLException;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.UUID;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import org.apache.commons.lang.StringUtils;
25 import org.apache.log4j.Logger;
26 import org.springframework.stereotype.Component;
27
28 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
29 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
30 import eu.etaxonomy.cdm.common.CdmUtils;
31 import eu.etaxonomy.cdm.io.common.IOValidator;
32 import eu.etaxonomy.cdm.io.common.mapping.DbImportAnnotationMapper;
33 import eu.etaxonomy.cdm.io.common.mapping.DbImportExtensionMapper;
34 import eu.etaxonomy.cdm.io.common.mapping.DbImportMapping;
35 import eu.etaxonomy.cdm.io.common.mapping.DbImportMethodMapper;
36 import eu.etaxonomy.cdm.io.common.mapping.DbImportObjectCreationMapper;
37 import eu.etaxonomy.cdm.io.common.mapping.DbNotYetImplementedMapper;
38 import eu.etaxonomy.cdm.io.common.mapping.IMappingImport;
39 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;
40 import eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.validation.CentralAfricaFernsTaxonImportValidator;
41 import eu.etaxonomy.cdm.model.agent.Team;
42 import eu.etaxonomy.cdm.model.agent.TeamOrPersonBase;
43 import eu.etaxonomy.cdm.model.common.AnnotationType;
44 import eu.etaxonomy.cdm.model.common.CdmBase;
45 import eu.etaxonomy.cdm.model.common.ExtensionType;
46 import eu.etaxonomy.cdm.model.common.TimePeriod;
47 import eu.etaxonomy.cdm.model.name.BotanicalName;
48 import eu.etaxonomy.cdm.model.name.INonViralName;
49 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
50 import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
51 import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
52 import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
53 import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
54 import eu.etaxonomy.cdm.model.name.Rank;
55 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
56 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
57 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
58 import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
59 import eu.etaxonomy.cdm.model.occurrence.Collection;
60 import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
61 import eu.etaxonomy.cdm.model.reference.Reference;
62 import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
63 import eu.etaxonomy.cdm.model.taxon.Synonym;
64 import eu.etaxonomy.cdm.model.taxon.Taxon;
65 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
66 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
67 import eu.etaxonomy.cdm.strategy.parser.TimePeriodParser;
68
69
70 /**
71 * @author a.mueller
72 * @created 20.02.2010
73 */
74 @Component
75 public class CentralAfricaFernsTaxonImport extends CentralAfricaFernsImportBase<TaxonBase> implements IMappingImport<TaxonBase, CentralAfricaFernsImportState>{
76 private static final Logger logger = Logger.getLogger(CentralAfricaFernsTaxonImport.class);
77
78 public static final UUID TNS_EXT_UUID = UUID.fromString("41cb0450-ac84-4d73-905e-9c7773c23b05");
79
80
81 private DbImportMapping<?,?> mapping;
82
83 //second path is not used anymore, there is now an ErmsTaxonRelationImport class instead
84 // private boolean isSecondPath = false;
85
86 private static final String pluralString = "taxa";
87 private static final String dbTableName = "[African pteridophytes]";
88 private static final Class<?> cdmTargetClass = TaxonBase.class;
89
90 public CentralAfricaFernsTaxonImport(){
91 super(pluralString, dbTableName, cdmTargetClass);
92 }
93
94
95 @Override
96 protected String getIdQuery() {
97 String strQuery = " SELECT [Taxon number] FROM " + dbTableName ;
98 return strQuery;
99 }
100
101 @Override
102 protected DbImportMapping<?,?> getMapping() {
103 if (mapping == null){
104 mapping = new DbImportMapping();
105
106 mapping.addMapper(DbImportObjectCreationMapper.NewInstance(this, "Taxon number", TAXON_NAMESPACE)); //id + tu_status
107
108 mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapTypes", ResultSet.class, CentralAfricaFernsImportState.class));
109 mapping.addMapper(DbImportAnnotationMapper.NewInstance("Notes", AnnotationType.EDITORIAL()));
110
111 mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapReferences", ResultSet.class, CentralAfricaFernsImportState.class));
112 mapping.addMapper(DbImportMethodMapper.NewInstance(this, "mapNomRemarks", ResultSet.class, CentralAfricaFernsImportState.class));
113
114 mapping.addMapper(DbImportExtensionMapper.NewInstance("Illustrations - non-original", CentralAfricaFernsTransformer.uuidIllustrationsNonOriginal, "Illustrations - non-original", "Illustrations - non-original", null));
115
116 // mapping.addMapper(DbImportTextDataCreationMapper.NewInstance("Illustrations - non-original", objectToCreateNamespace, dbTaxonFkAttribute, this.TAXON_NAMESPACE, "Illustrations - non-original", Language.ENGLISH(), Feature, null);
117 // mapping.addMapper(DbImportTextDataCreationMapper.NewInstance(dbIdAttribute, objectToCreateNamespace, dbTaxonFkAttribute, taxonNamespace, dbTextAttribute, Language.ENGLISH(), Feature.ECOLOGY(), null));
118
119 //not yet implemented or ignore
120 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Types XXX", "Method Mapper does not work yet. Needs implementation for all 5 types. FIXMEs in implementation"));
121
122 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Basionym of", "Needs better understanding"));
123 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Synonym of", "Needs better understanding. Strange values like "));
124
125
126 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Chromosome number" , "Wrong data. Seems to be 'reference full'"));
127
128 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Book Publisher & Place" , "How to access the reference via String mapper?"));
129
130 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Reprint no" , "What's this?"));
131 mapping.addMapper(DbNotYetImplementedMapper.NewInstance("Date verified" , "Needed?"));
132
133
134 //
135 // UUID credibilityUuid = ErmsTransformer.uuidCredibility;
136 // mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_credibility", credibilityUuid, "credibility", "credibility", "credibility")); //Werte: null, unknown, marked for deletion
137 //
138 //ignore
139 // mapping.addMapper(DbIgnoreMapper.NewInstance("cache_citation", "citation cache not needed in PESI"));
140
141 //not yet implemented or ignore
142 // mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_hidden", "Needs DbImportMarkerMapper implemented"));
143
144 }
145 return mapping;
146 }
147
148 /* (non-Javadoc)
149 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getRecordQuery(eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportConfigurator)
150 */
151 @Override
152 protected String getRecordQuery(CentralAfricaFernsImportConfigurator config) {
153 String strSelect = " SELECT * ";
154 String strFrom = " FROM [African pteridophytes] as ap";
155 String strWhere = " WHERE ( ap.[taxon number] IN (" + ID_LIST_TOKEN + ") )";
156 String strOrderBy = " ORDER BY [Taxon number]";
157 String strRecordQuery = strSelect + strFrom + strWhere + strOrderBy;
158 return strRecordQuery;
159 }
160
161
162 @Override
163 public Map<Object, Map<String, ? extends CdmBase>> getRelatedObjectsForPartition(ResultSet rs, CentralAfricaFernsImportState state) {
164 // String nameSpace;
165 // Class<?> cdmClass;
166 // Set<String> idSet;
167 Map<Object, Map<String, ? extends CdmBase>> result = new HashMap<Object, Map<String, ? extends CdmBase>>();
168
169 try{
170 Set<String> nameIdSet = new HashSet<String>();
171 Set<String> referenceIdSet = new HashSet<String>();
172 while (rs.next()){
173 // handleForeignKey(rs, nameIdSet, "PTNameFk");
174 // handleForeignKey(rs, referenceIdSet, "PTRefFk");
175 }
176
177 //reference map
178 // nameSpace = "Reference";
179 // cdmClass = Reference.class;
180 // Map<String, Person> referenceMap = (Map<String, Person>)getCommonService().getSourcedObjectsByIdInSource(Person.class, teamIdSet, nameSpace);
181 // result.put(Reference.class, referenceMap);
182
183 } catch (SQLException e) {
184 throw new RuntimeException(e);
185 }
186 return result;
187 }
188
189 private TaxonBase mapTypes(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
190 TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
191 TaxonNameBase name = taxonBase.getName();
192 for (int i = 1; i <= 5; i++){
193 String[] typeInfo = new String[3];
194 typeInfo = getTypeInfo(rs, i);
195 if (StringUtils.isBlank(typeInfo[0]) && StringUtils.isBlank(typeInfo[1]) && StringUtils.isBlank(typeInfo[2])){
196 continue;
197 }
198 makeSingleType(state, name, typeInfo[0], typeInfo[1], typeInfo[2]);
199 }
200 return taxonBase;
201 }
202
203
204 private String[] getTypeInfo(ResultSet rs, int i) throws SQLException {
205 String[] typeInfo = new String[3];
206 String number;
207 if (i == 1){
208 number = "";
209 }else{
210 number = String.valueOf(i);
211 }
212 typeInfo[0] = rs.getString("Type" + number);
213 typeInfo[1] = rs.getString("Type collector and number" + number);
214 typeInfo[2] = rs.getString("Type location" + number);
215
216 return typeInfo;
217 }
218
219
220
221 private void makeSingleType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocationString) {
222 if (name.getRank().isHigher(Rank.SPECIES())){
223 //TODO move to TaxonRelationImport
224 handleNameType(state, name, typeString, typeCollectorString, typeLocationString);
225 }else{
226 handleSpecimenType(state, name, typeString, typeCollectorString, typeLocationString);
227 }
228 }
229
230
231
232 private void handleSpecimenType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocationString) {
233 List<SpecimenTypeDesignation> designations = new ArrayList<SpecimenTypeDesignation>();
234 typeLocationString = CdmUtils.Nz(typeLocationString);
235 if (typeLocationString.equalsIgnoreCase("not located")){
236
237 }else{
238 String[] splits = typeLocationString.split(";");
239 for (String split : splits){
240 List<SpecimenTypeDesignation> splitDesignations = handleTypeLocationPart(state, typeString, typeCollectorString, split);
241 designations.addAll(splitDesignations);
242 }
243 }
244 if (designations.size() == 0){
245 logger.error(state.getTaxonNumber() + " - No designations defined. TypeString: " + CdmUtils.Nz(typeString) + ", CollectorString: " + typeCollectorString);
246 }
247 //type and collector
248 DerivedUnitFacade lastFacade = null;
249 for (SpecimenTypeDesignation designation: designations){
250 name.addTypeDesignation(designation, false);
251 if (typeString != null && (typeString.contains("Not designated.")|| typeString.contains("No type designated."))){
252 designation.setNotDesignated(true);
253 }
254
255 DerivedUnit specimen = designation.getTypeSpecimen();
256
257 if (lastFacade != null){
258 lastFacade.addDuplicate(specimen);
259 }else{
260
261 try {
262 lastFacade = DerivedUnitFacade.NewInstance(specimen);
263 } catch (DerivedUnitFacadeNotSupportedException e) {
264 throw new RuntimeException(e);
265 }
266
267 //TODO not so nice
268 lastFacade.setLocality(typeString);
269 makeTypeCollectorInfo(lastFacade, typeCollectorString);
270
271 }
272 }
273
274 }
275
276
277
278 private List<SpecimenTypeDesignation> handleTypeLocationPart(CentralAfricaFernsImportState state,
279 String typeString, String typeCollectorString, String typeLocationPart) {
280 List<SpecimenTypeDesignation> result = new ArrayList<SpecimenTypeDesignation>();
281 String[] splits = typeLocationPart.split(",");
282 //see also SpecimenTypeParser
283 String typeTypePattern = "(holo.|lecto.|iso.|isolecto.|syn.|isosyn.|neo.|isoneo.)";
284 String collectionPattern = "^[A-Z]+(\\-[A-Z]+)?";
285 String numberPattern = "([0-9]+([\\-\\s\\.\\/][0-9]+)?)?";
286 String addInfoPattern = "[!\\+\\?]?";
287 String typeCollectionPattern = collectionPattern + "\\s?" + numberPattern + addInfoPattern;
288 SpecimenTypeDesignation lastDesignation = null;
289
290 for (String split: splits){
291 split = split.trim();
292 if (StringUtils.isBlank(split)){
293 continue;
294 }else if(split.trim().startsWith("designated by")){
295 split = handleDesignatedBy(lastDesignation, split);
296 }else if (split.trim().matches(typeTypePattern)){
297 makeSpecimentTypeStatus(lastDesignation, split);
298 }else if(split.matches(typeCollectionPattern)){
299
300 lastDesignation = makeSpecimenTypeCollection(lastDesignation, split, collectionPattern, numberPattern, addInfoPattern);
301 }else if(split.equalsIgnoreCase("not located")){
302 lastDesignation = makeCachedSpecimenDesignation(split);
303 }else{
304 logger.error(state.getTaxonNumber() + " - Unknown type location part: " + split);
305 if (lastDesignation == null){
306 lastDesignation = makeCachedSpecimenDesignation(split);
307 }
308 }
309 if (lastDesignation != null && ! result.contains(lastDesignation)){
310 result.add(lastDesignation);
311 }else if (lastDesignation == null){
312 logger.warn("Last Designation is null");
313 }
314 }
315
316 return result;
317 }
318
319
320
321 /**
322 * @param split
323 * @return
324 */
325 private SpecimenTypeDesignation makeCachedSpecimenDesignation(String split) {
326 SpecimenTypeDesignation lastDesignation;
327 lastDesignation = SpecimenTypeDesignation.NewInstance();
328 DerivedUnit specimen = DerivedUnit.NewPreservedSpecimenInstance();
329 specimen.setTitleCache(split, true);
330 lastDesignation.setTypeSpecimen(specimen);
331 return lastDesignation;
332 }
333
334
335
336 private SpecimenTypeDesignation makeSpecimenTypeCollection(SpecimenTypeDesignation designation, String collectionString, String strCollectionPattern, String strNumberPattern, String strAddInfoPattern) {
337 SpecimenTypeDesignation result = SpecimenTypeDesignation.NewInstance();
338 DerivedUnit specimen = DerivedUnit.NewPreservedSpecimenInstance();
339 result.setTypeSpecimen(specimen);
340
341 //collection
342 Pattern collectionPattern = Pattern.compile(strCollectionPattern);
343 Matcher matcher = collectionPattern.matcher(collectionString);
344 if (! matcher.find()){
345 throw new RuntimeException("collectionString doesn't match: " + collectionString);
346 }
347 String strCollection = matcher.group();
348 Collection collection = getCollection(strCollection);
349 specimen.setCollection(collection);
350 collectionString = collectionString.substring(strCollection.length()).trim();
351
352
353 //collection number
354 Pattern numberPattern = Pattern.compile(strNumberPattern);
355 matcher = numberPattern.matcher(collectionString);
356 if (matcher.find()){
357 String strNumber = matcher.group();
358 collectionString = collectionString.substring(strNumber.length()).trim();
359 if (StringUtils.isNotBlank(strNumber)){
360 specimen.setCatalogNumber(strNumber);
361 }
362 }else{
363 //throw new RuntimeException("numberString doesn't match: " + collectionString);
364 }
365
366 //additional info
367 Pattern addInfoPattern = Pattern.compile(strAddInfoPattern);
368 matcher = addInfoPattern.matcher(collectionString);
369 if (matcher.find()){
370 String strAddInfo = matcher.group();
371 collectionString = collectionString.substring(strAddInfo.length()).trim();
372 if (StringUtils.isBlank(strAddInfo)){
373 //do nothing
374 }else if (strAddInfo.equals("!")){
375 //TODO add seen by author
376 }else if (strAddInfo.equals("?")){
377 //TODO add doubtful
378 }else if (strAddInfo.equals("+")){
379 //TODO add +
380 }
381 }else{
382 //throw new RuntimeException("addInfoString doesn't match: " + collectionString);
383 }
384 if (StringUtils.isNotBlank(collectionString)){
385 logger.error("Collection string is not empty: " + collectionString );
386 }
387 return result;
388 }
389
390
391
392 private Collection getCollection(String strCollection) {
393 //TODO use BCI and deduplication
394 Collection result = Collection.NewInstance();
395 return result;
396 }
397
398
399
400 private void makeSpecimentTypeStatus(SpecimenTypeDesignation designation, String type) {
401 SpecimenTypeDesignationStatus status;
402 if (type.equalsIgnoreCase("iso.")){
403 status = SpecimenTypeDesignationStatus.ISOTYPE();
404 }else if (type.equalsIgnoreCase("isolecto.")){
405 status = SpecimenTypeDesignationStatus.ISOLECTOTYPE();
406 }else if (type.equalsIgnoreCase("syn.")){
407 status = SpecimenTypeDesignationStatus.SYNTYPE();
408 }else if (type.equalsIgnoreCase("holo.")){
409 status = SpecimenTypeDesignationStatus.HOLOTYPE();
410 }else if (type.equalsIgnoreCase("lecto.")){
411 status = SpecimenTypeDesignationStatus.LECTOTYPE();
412 }else if (type.equalsIgnoreCase("isosyn.")){
413 status = SpecimenTypeDesignationStatus.ISOSYNTYPE();
414 }else if (type.equalsIgnoreCase("neo.")){
415 status = SpecimenTypeDesignationStatus.NEOTYPE();
416 }else if (type.equalsIgnoreCase("isoneo.")){
417 status = SpecimenTypeDesignationStatus.ISONEOTYPE();
418 }else{
419 logger.error("Type Status not supported: " + type);
420 throw new RuntimeException("Type Status not supported: " + type);
421 }
422 if (designation == null){
423 logger.error("Designation is null");
424 }else{
425 designation.setTypeStatus(status);
426 }
427 }
428
429
430
431 private void handleNameType(CentralAfricaFernsImportState state, TaxonNameBase name, String typeString, String typeCollectorString, String typeLocation) {
432 String originalString = typeString; //just for testing
433 if (StringUtils.isNotBlank(typeCollectorString)){
434 logger.error(state.getTaxonNumber() + " - Type collector string for name type is not empty: " + typeCollectorString);
435 }
436 if (StringUtils.isNotBlank(typeLocation)){
437 logger.error(state.getTaxonNumber() + " - Type location string for name type is not empty: " + typeLocation);
438 }
439 NameTypeDesignation nameTypeDesignation = NameTypeDesignation.NewInstance();
440 NameTypeDesignationStatus status = null;
441 if (StringUtils.isBlank(typeString)){
442 logger.warn(state.getTaxonNumber() + " - TypeString is empty");
443 }
444 if (typeString.startsWith("None designated.")){
445 nameTypeDesignation.setNotDesignated(true);
446 typeString = typeString.replaceFirst("None designated\\.", "").trim();
447 }
448 if (typeString.contains("Lectotype: ")|| typeString.contains(", lecto." )){
449 status = NameTypeDesignationStatus.LECTOTYPE();
450 typeString = typeString.replace("Lectotype: ", "");
451 typeString = typeString.replace(", lecto.", "");
452 typeString = handleDesignatedBy(nameTypeDesignation, typeString);
453 }else{
454 typeString = handleDesignatedBy(nameTypeDesignation, typeString);
455 }
456
457 // String strSecondNamePattern = "([^\\(]*|\\(.*\\))+;.+"; //never ending story
458 String strSecondNamePattern = ".+;.+";
459 String firstName;
460 String secondName = null;
461 if (typeString.matches(strSecondNamePattern)){
462 String[] split = typeString.split(";");
463 firstName = split[0].trim();
464 secondName = split[1].trim();
465 if (split.length > 2){
466 logger.warn(state.getTaxonNumber() + " - There are more than 2 name types: " + typeString);
467 }
468 }else{
469 firstName = typeString;
470 }
471 if (StringUtils.isNotBlank(firstName)){
472 BotanicalName[] nameTypeNames = getNameTypeName(firstName);
473 BotanicalName nameTypeName = nameTypeNames[0];
474 BotanicalName nameTypeAcceptedName = nameTypeNames[1];
475 nameTypeDesignation.setTypeName(nameTypeName);
476 if (nameTypeName.isProtectedTitleCache()){
477 logger.error(state.getTaxonNumber() + " - Name type could not be parsed: " + nameTypeName.getTitleCache());
478 }
479 if (! nameTypeName.getRank().equals(Rank.SPECIES())){
480 logger.warn(state.getTaxonNumber() + " - Name type is not of rank species: " + nameTypeName.getTitleCache());
481 }
482 }
483 if (StringUtils.isNotBlank(secondName)){
484 TaxonNameBase secondNameType = handleSecondNameTypeName(secondName);
485 if (secondNameType.isProtectedTitleCache()){
486 logger.error(state.getTaxonNumber() + " - Second name type could not be parsed: " + secondNameType.getTitleCache());
487 }
488 if (! secondNameType.getRank().equals(Rank.SPECIES())){
489 logger.error(state.getTaxonNumber() + " - Second name type is not of rank species: " + secondNameType.getTitleCache());
490 }
491
492 }
493 nameTypeDesignation.setTypeStatus(status);
494 name.addTypeDesignation(nameTypeDesignation, false);
495
496 }
497
498
499
500 private TaxonNameBase handleSecondNameTypeName(String strName) {
501 //TODO needs feedbacke from Thomas
502 logger.info("Not yet implemented");
503 if (strName.endsWith(",")){
504 strName = strName.substring(0, strName.length() -1);
505 }
506 BotanicalName result = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(strName, NomenclaturalCode.ICNAFP, Rank.SPECIES());
507 return result;
508 }
509
510
511
512 private BotanicalName[] getNameTypeName(String strName) {
513 //TODO implement get existing names
514 logger.info("Not yet fully implemented");
515
516 BotanicalName[] result = new BotanicalName[2];
517 if (strName.endsWith(",")){
518 strName = strName.substring(0, strName.length() -1);
519 }
520 String acceptedName;
521 String acceptedNamePattern = "\\(.*\\)\\.?$";
522 if (strName.matches(".*" + acceptedNamePattern)){
523 int accStart = strName.lastIndexOf("(");
524 String notAcceptedName = strName.substring(0, accStart -1 );
525 acceptedName = strName.substring(accStart + 1, strName.length() - 1);
526 if (acceptedName.endsWith(")")){
527 acceptedName = acceptedName.substring(0, acceptedName.length()-1);
528 }
529 acceptedName = acceptedName.replaceFirst("=", "").trim();
530 result[1] = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(acceptedName, NomenclaturalCode.ICNAFP, null);
531 strName = notAcceptedName;
532 }
533
534 result[0] = (BotanicalName)NonViralNameParserImpl.NewInstance().parseFullName(strName, NomenclaturalCode.ICNAFP, Rank.SPECIES());
535 return result;
536 }
537
538
539
540 private String handleDesignatedBy(TypeDesignationBase<?> typeDesignation, String typeString) {
541 String[] splitDesignated = typeString.split(", designated by ");
542 if (splitDesignated.length > 1){
543 Reference designationCitation = getDesignationCitation(typeDesignation, splitDesignated[1]);
544 typeDesignation.setCitation(designationCitation);
545 if (splitDesignated.length > 2){
546 throw new IllegalStateException("More than one designation is not expected");
547 }
548 }
549 return splitDesignated[0].trim();
550 }
551
552
553
554 private Reference getDesignationCitation(TypeDesignationBase<?> typeDesignation, String citationString) {
555 // TODO try to find an existing Reference
556 Reference result = ReferenceFactory.newGeneric();
557 String strBracketPattern = "\\((10 Oct. )?\\d{4}:\\s?(\\d{1,3}(--\\d{1,3})?|[XLVI]{1,7}|\\.{1,8})\\)\\.?";
558
559 String strStandardPattern = ".*" + strBracketPattern;
560 // strStandardPattern = ".*";
561 if (Pattern.matches(strStandardPattern, citationString)){
562 parseStandardPattern(typeDesignation, result, citationString, strBracketPattern);
563 }else{
564 logger.error("Can't parse designation citation: " + citationString);
565 result.setTitleCache(citationString);
566 }
567 return result;
568 }
569
570
571
572 private void parseStandardPattern(TypeDesignationBase typeDesignation, Reference result, String citationString, String bracketPattern) {
573 String authorPart = citationString.split(bracketPattern)[0];
574 String bracket = citationString.substring(authorPart.length()+1, citationString.length()-1).trim();
575 authorPart = authorPart.trim();
576 if (bracket.endsWith(")")){
577 bracket = bracket.substring(0, bracket.length()-1);
578 }
579 Team team = Team.NewTitledInstance(authorPart, authorPart);
580 result.setAuthorship(team);
581 String[] bracketSplit = bracket.split(":");
582 TimePeriod datePublished = TimePeriodParser.parseString(bracketSplit[0].trim());
583 result.setDatePublished(datePublished);
584 String citationMicroReference = bracketSplit[1].trim();
585 citationMicroReference = citationMicroReference.replace("--", "-");
586 typeDesignation.setCitationMicroReference(citationMicroReference);
587 }
588
589
590
591 private void makeTypeCollectorInfo(DerivedUnitFacade specimen, String collectorAndNumberString) {
592 if (StringUtils.isBlank(collectorAndNumberString)){
593 return;
594 }
595 String reNumber = "(s\\.n\\.|\\d.*)";
596 Pattern reNumberPattern = Pattern.compile(reNumber);
597 Matcher matcher = reNumberPattern.matcher(collectorAndNumberString);
598
599 if ( matcher.find()){
600 int numberStart = matcher.start();
601 String number = collectorAndNumberString.substring(numberStart).trim();
602 if (numberStart > 0){
603 numberStart = numberStart -1;
604 }
605 String collectorString = collectorAndNumberString.substring(0, numberStart).trim();
606 specimen.setFieldNumber(number);
607 TeamOrPersonBase team = getTeam(collectorString);
608 specimen.setCollector(team);
609
610 }else{
611 logger.warn("collector string did not match number pattern: " + collectorAndNumberString);
612
613 }
614 }
615
616
617 private TeamOrPersonBase getTeam(String teamString) {
618 //TODO check existing team
619 TeamOrPersonBase result = Team.NewTitledInstance(teamString, teamString);
620 return result;
621 }
622
623
624
625 /**
626 * for internal use only, used by MethodMapper
627 */
628 private TaxonBase mapReferences(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException{
629 String taxonNumber = state.getTaxonNumber();
630 String referenceFullString = rs.getString("Reference full");
631 String referenceAbbreviatedString = rs.getString("Reference - abbreviated");
632 String volume = rs.getString("Book / Journal volume");
633 String pages = rs.getString("Book / Journal pages");
634 String illustrations = rs.getString("Illustration/s");
635
636 String fascicle = rs.getString("Book / Journal fascicle");
637 String part = rs.getString("Book / Journal part");
638 String paperTitle = rs.getString("Book / Paper title");
639
640 String datePublishedString = rs.getString("Date published");
641 String referenceString = referenceFullString;
642 if (StringUtils.isBlank(referenceString)){
643 referenceString = referenceAbbreviatedString;
644 }
645
646 TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
647 if (StringUtils.isNotBlank(referenceString) || StringUtils.isNotBlank(volume) ||
648 StringUtils.isNotBlank(pages) || StringUtils.isNotBlank(illustrations) ||
649 StringUtils.isNotBlank(datePublishedString) || StringUtils.isNotBlank(paperTitle)){
650 INonViralName name = taxonBase.getName();
651 Reference reference = ReferenceFactory.newGeneric();
652 reference.setAuthorship(name.getCombinationAuthorship());
653 reference.setTitle(referenceString);
654 reference.setVolume(volume);
655 reference.setEdition(part);
656 Reference inreference = null;
657 //TODO parser
658 TimePeriod datePublished = TimePeriodParser.parseString(datePublishedString);
659 reference.setDatePublished(datePublished);
660 if (StringUtils.isNotBlank(paperTitle)){
661 Reference innerReference = ReferenceFactory.newGeneric();
662 innerReference.setDatePublished(datePublished);
663 name.setNomenclaturalReference(innerReference);
664 innerReference.setInReference(reference);
665 reference = innerReference;
666 }else{
667 name.setNomenclaturalReference(reference);
668 }
669
670 //details
671 String details = CdmUtils.concat(", ", pages, illustrations);
672 details = StringUtils.isBlank(details) ? null : details.trim();
673 name.setNomenclaturalMicroReference(details);
674 try {
675 UUID uuidFascicle = state.getTransformer().getExtensionTypeUuid("fascicle");
676 ExtensionType extensionType = getExtensionType(state, uuidFascicle, "Fascicle", "Fascicle", null);
677 reference.addExtension(fascicle, extensionType);
678 } catch (UndefinedTransformerMethodException e) {
679 e.printStackTrace();
680 }
681
682 }else{
683 logger.warn(taxonNumber + " - Taxon has no reference");
684 }
685 return taxonBase;
686 }
687
688 /**
689 * for internal use only, used by MethodMapper
690 * @throws Exception
691 */
692 private TaxonBase mapNomRemarks(ResultSet rs, CentralAfricaFernsImportState state) throws Exception{
693 try {
694 String taxonNumber = state.getTaxonNumber();
695 String nomRemarksString = rs.getString("Nom remarks");
696 String taxonStatus = rs.getString("Current/Synonym");
697
698 TaxonBase<?> taxonBase = state.getRelatedObject(state.CURRENT_OBJECT_NAMESPACE, state.CURRENT_OBJECT_ID, TaxonBase.class);
699 if (StringUtils.isNotBlank(nomRemarksString)){
700 INonViralName name = taxonBase.getName();
701 parseNomRemark(state, name, nomRemarksString.trim(),taxonStatus, taxonNumber);
702 }
703 return taxonBase;
704 } catch (Exception e) {
705 throw e;
706 }
707 }
708
709
710 private void parseNomRemark(CentralAfricaFernsImportState state, INonViralName name, String nomRemarksString, String taxonStatus, String taxonNumber) {
711
712 if (nomRemarksString.equalsIgnoreCase("comb. illeg.")){
713 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.COMBINATION_ILLEGITIMATE()));
714 return;
715 // }else if (nomRemarksString.startsWith("comb. inval.")){
716 // //TODO
717 // nomRemarksString = nomRemarksString.replace("comb. inval.", "");
718 // }else if (nomRemarksString.equals("comb. nov.")){
719 // name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.COMBINATION_NOVUM);
720 }else if (nomRemarksString.equals("nom. ambig.")){
721 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.AMBIGUOUS()));
722 return;
723 }else if (nomRemarksString.matches("nom\\. cons(erv)?\\.")){
724 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.CONSERVED()));
725 return;
726 }else if (nomRemarksString.matches("nom\\. illeg(it)?\\.")){
727 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.ILLEGITIMATE()));
728 return;
729 }else if (nomRemarksString.matches("nom\\. inval(id)?\\.")){
730 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.INVALID()));
731 return;
732 }else if (nomRemarksString.matches("nom\\. nov\\.")){
733 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.NOVUM()));
734 return;
735 }else if (nomRemarksString.matches("nom\\. nud\\.")){
736 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.NUDUM()));
737 return;
738 }else if (nomRemarksString.matches("nom\\. superfl\\.")){
739 name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.SUPERFLUOUS()));
740 return;
741 }else if (nomRemarksString.matches("p(\\.|ro\\s)?p(\\.|arte)")){
742 //pro parte is handled in taxon relationship import
743 if (! taxonStatus.equals("s")){
744 logger.warn(" - " + taxonNumber + " Pro parte synonym is not of type synonym");
745 }
746 return;
747 }else if (nomRemarksString.matches("as '.*'")){
748 String nameAsString = nomRemarksString.substring(4, nomRemarksString.length()-1);
749 //TODO discuss make it a name relationship
750 UUID uuidPublishedAs = CentralAfricaFernsTransformer.uuidNamePublishedAs;
751 ExtensionType extensionType = getExtensionType(state, uuidPublishedAs, "Name published as", "Name published as", "as");
752 name.addExtension(nameAsString, extensionType);
753 return;
754 }
755
756
757 if (StringUtils.isNotBlank(nomRemarksString)){
758 ExtensionType extensionType = getExtensionType(state, CentralAfricaFernsTransformer.uuidNomenclaturalRemarks, "Nomenclatural remarks", "Nomenclatural remarks", null);
759 name.addExtension(nomRemarksString, extensionType);
760 }
761
762
763
764
765 }
766
767
768
769 /* (non-Javadoc)
770 * @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet)
771 */
772 @Override
773 public TaxonBase createObject(ResultSet rs, CentralAfricaFernsImportState state) throws SQLException {
774 BotanicalName taxonName = BotanicalName.NewInstance(null);
775 Reference sec = state.getConfig().getSourceReference();
776
777 String taxonNumber = rs.getString("Taxon number");
778 state.setTaxonNumber(taxonNumber);
779
780 String orderName = rs.getString("Order name");
781 String subOrderName = rs.getString("Suborder name");
782 String familyName = rs.getString("Family name");
783 String subFamilyName = rs.getString("Subfamily name");
784 String tribusName = rs.getString("Tribus name");
785 String subTribusName = rs.getString("Subtribus name");
786 String sectionName = rs.getString("Section name");
787 String genusName = rs.getString("Genus name");
788 String subGenusName = rs.getString("Subgenus name");
789 String seriesName = rs.getString("Series name");
790 String specificEpihet = rs.getString("Specific epihet");
791 String subspeciesName = rs.getString("Subspecies name");
792 String varietyName = rs.getString("Variety name");
793 String subFormaName = rs.getString("Subforma");
794 String subVariety = rs.getString("Subvariery");
795 String formaName = rs.getString("Forma name");
796 String subsectionName = rs.getString("Subsection name");
797
798 String status = rs.getString("Current/Synonym");
799
800 TaxonBase taxon = makeTaxon(taxonName, sec, taxonNumber, status);
801
802 // Integer parent3Rank = rs.getInt("parent3rank");
803
804 //rank and epithets
805 Rank lowestRank = setLowestUninomial(taxonName, orderName, subOrderName, familyName, subFamilyName, tribusName, subTribusName,genusName);
806 lowestRank = setLowestInfraGeneric(taxonName, lowestRank, subGenusName, sectionName, subsectionName, seriesName);
807 if (StringUtils.isNotBlank(specificEpihet)){
808 taxonName.setSpecificEpithet(specificEpihet);
809 lowestRank = Rank.SPECIES();
810 }
811 lowestRank = setLowestInfraSpecific(taxonName, lowestRank, subspeciesName, varietyName, subVariety, formaName,subFormaName);
812
813 taxonName.setRank(lowestRank);
814 state.setCurrentRank(taxonName.getRank());
815 setAuthor(taxonName, rs, taxonNumber, false);
816
817 //add original source for taxon name (taxon original source is added in mapper
818 // Reference citation = state.getConfig().getSourceReference();
819 // addOriginalSource(taxonName, taxonNumber, TAXON_NAMESPACE, citation);
820 return taxon;
821
822 }
823
824
825
826 /**
827 * Creates the taxon object depending on name, sec and status
828 * @param taxonName
829 * @param sec
830 * @param taxonNumber
831 * @param status
832 * @return
833 */
834 private TaxonBase makeTaxon(BotanicalName taxonName, Reference sec, String taxonNumber, String status) {
835 TaxonBase taxon;
836 if ("c".equalsIgnoreCase(status)|| "incertus".equalsIgnoreCase(status) ){
837 taxon = Taxon.NewInstance(taxonName, sec);
838 if ("incertus".equalsIgnoreCase(status)){
839 taxon.setDoubtful(true);
840 }
841 }else if ("s".equalsIgnoreCase(status)){
842 taxon = Synonym.NewInstance(taxonName, sec);
843 }else{
844 logger.warn(taxonNumber + ": Status not given for taxon " );
845 taxon = Taxon.NewUnknownStatusInstance(taxonName, sec);
846 }
847 return taxon;
848 }
849
850
851 private Rank setLowestInfraSpecific(BotanicalName taxonName, Rank lowestRank, String subspeciesName, String varietyName,
852 String subVariety, String formaName, String subFormaName) {
853 if (StringUtils.isNotBlank(subFormaName)){
854 taxonName.setInfraSpecificEpithet(subFormaName);
855 return Rank.SUBFORM();
856 }else if (StringUtils.isNotBlank(formaName)){
857 taxonName.setInfraSpecificEpithet(formaName);
858 return Rank.FORM();
859 }else if (StringUtils.isNotBlank(subVariety)){
860 taxonName.setInfraSpecificEpithet(subVariety);
861 return Rank.SUBVARIETY();
862 }else if (StringUtils.isNotBlank(varietyName)){
863 taxonName.setInfraSpecificEpithet(varietyName);
864 return Rank.VARIETY();
865 }else if (StringUtils.isNotBlank(subspeciesName)){
866 taxonName.setInfraSpecificEpithet(subspeciesName);
867 return Rank.SUBSPECIES();
868 }else{
869 return lowestRank;
870 }
871 }
872
873
874
875 private Rank setLowestInfraGeneric(BotanicalName taxonName, Rank lowestRank, String subGenusName, String sectionName, String subSectionName, String seriesName) {
876 if (StringUtils.isNotBlank(seriesName)){
877 taxonName.setInfraGenericEpithet(seriesName);
878 return Rank.SERIES();
879 }else if (StringUtils.isNotBlank(subSectionName)){
880 taxonName.setInfraGenericEpithet(subSectionName);
881 return Rank.SUBSECTION_BOTANY();
882 }else if (StringUtils.isNotBlank(sectionName)){
883 taxonName.setInfraGenericEpithet(sectionName);
884 return Rank.SECTION_BOTANY();
885 }else if (StringUtils.isNotBlank(subGenusName)){
886 taxonName.setInfraGenericEpithet(subGenusName);
887 return Rank.SUBGENUS();
888 }else{
889 return lowestRank;
890 }
891 }
892
893
894
895 private Rank setLowestUninomial(BotanicalName taxonName, String orderName, String subOrderName, String familyName, String subFamilyName,
896 String tribusName, String subTribusName, String genusName) {
897
898 if (StringUtils.isNotBlank(genusName)){
899 taxonName.setGenusOrUninomial(genusName);
900 return Rank.GENUS();
901 }else if (StringUtils.isNotBlank(subTribusName)){
902 taxonName.setGenusOrUninomial(subTribusName);
903 return Rank.SUBTRIBE();
904 }else if (StringUtils.isNotBlank(tribusName)){
905 taxonName.setGenusOrUninomial(tribusName);
906 return Rank.TRIBE();
907 }else if (StringUtils.isNotBlank(subFamilyName)){
908 taxonName.setGenusOrUninomial(subFamilyName);
909 return Rank.SUBFAMILY();
910 }else if (StringUtils.isNotBlank(familyName)){
911 taxonName.setGenusOrUninomial(familyName);
912 return Rank.FAMILY();
913 }else if (StringUtils.isNotBlank(subOrderName)){
914 taxonName.setGenusOrUninomial(subOrderName);
915 return Rank.SUBORDER();
916 }else if (StringUtils.isNotBlank(orderName)){
917 taxonName.setGenusOrUninomial(orderName);
918 return Rank.ORDER();
919 }else{
920 return null;
921 }
922 }
923
924
925 /* (non-Javadoc)
926 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
927 */
928 @Override
929 protected boolean doCheck(CentralAfricaFernsImportState state){
930 IOValidator<CentralAfricaFernsImportState> validator = new CentralAfricaFernsTaxonImportValidator();
931 return validator.validate(state);
932 }
933
934
935 /* (non-Javadoc)
936 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
937 */
938 @Override
939 protected boolean isIgnore(CentralAfricaFernsImportState state){
940 return ! state.getConfig().isDoTaxa();
941 }
942
943
944
945 }