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