2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.io
.eflora
.centralAfrica
.ferns
;
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
;
20 import java
.util
.UUID
;
21 import java
.util
.regex
.Matcher
;
22 import java
.util
.regex
.Pattern
;
24 import org
.apache
.commons
.lang
.StringUtils
;
25 import org
.apache
.log4j
.Logger
;
26 import org
.springframework
.stereotype
.Component
;
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
;
75 public class CentralAfricaFernsTaxonImport
extends CentralAfricaFernsImportBase
<TaxonBase
> implements IMappingImport
<TaxonBase
, CentralAfricaFernsImportState
>{
76 private static final Logger logger
= Logger
.getLogger(CentralAfricaFernsTaxonImport
.class);
78 public static final UUID TNS_EXT_UUID
= UUID
.fromString("41cb0450-ac84-4d73-905e-9c7773c23b05");
81 private DbImportMapping
<?
,?
> mapping
;
83 //second path is not used anymore, there is now an ErmsTaxonRelationImport class instead
84 // private boolean isSecondPath = false;
86 private static final String pluralString
= "taxa";
87 private static final String dbTableName
= "[African pteridophytes]";
88 private static final Class
<?
> cdmTargetClass
= TaxonBase
.class;
90 public CentralAfricaFernsTaxonImport(){
91 super(pluralString
, dbTableName
, cdmTargetClass
);
96 protected String
getIdQuery() {
97 String strQuery
= " SELECT [Taxon number] FROM " + dbTableName
;
102 protected DbImportMapping
<?
,?
> getMapping() {
103 if (mapping
== null){
104 mapping
= new DbImportMapping();
106 mapping
.addMapper(DbImportObjectCreationMapper
.NewInstance(this, "Taxon number", TAXON_NAMESPACE
)); //id + tu_status
108 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapTypes", ResultSet
.class, CentralAfricaFernsImportState
.class));
109 mapping
.addMapper(DbImportAnnotationMapper
.NewInstance("Notes", AnnotationType
.EDITORIAL()));
111 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapReferences", ResultSet
.class, CentralAfricaFernsImportState
.class));
112 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapNomRemarks", ResultSet
.class, CentralAfricaFernsImportState
.class));
114 mapping
.addMapper(DbImportExtensionMapper
.NewInstance("Illustrations - non-original", CentralAfricaFernsTransformer
.uuidIllustrationsNonOriginal
, "Illustrations - non-original", "Illustrations - non-original", null));
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));
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"));
122 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Basionym of", "Needs better understanding"));
123 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Synonym of", "Needs better understanding. Strange values like "));
126 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Chromosome number" , "Wrong data. Seems to be 'reference full'"));
128 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Book Publisher & Place" , "How to access the reference via String mapper?"));
130 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Reprint no" , "What's this?"));
131 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Date verified" , "Needed?"));
135 // UUID credibilityUuid = ErmsTransformer.uuidCredibility;
136 // mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_credibility", credibilityUuid, "credibility", "credibility", "credibility")); //Werte: null, unknown, marked for deletion
139 // mapping.addMapper(DbIgnoreMapper.NewInstance("cache_citation", "citation cache not needed in PESI"));
141 //not yet implemented or ignore
142 // mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_hidden", "Needs DbImportMarkerMapper implemented"));
149 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getRecordQuery(eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportConfigurator)
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
;
163 public Map
<Object
, Map
<String
, ?
extends CdmBase
>> getRelatedObjectsForPartition(ResultSet rs
, CentralAfricaFernsImportState state
) {
165 // Class<?> cdmClass;
166 // Set<String> idSet;
167 Map
<Object
, Map
<String
, ?
extends CdmBase
>> result
= new HashMap
<Object
, Map
<String
, ?
extends CdmBase
>>();
170 Set
<String
> nameIdSet
= new HashSet
<String
>();
171 Set
<String
> referenceIdSet
= new HashSet
<String
>();
173 // handleForeignKey(rs, nameIdSet, "PTNameFk");
174 // handleForeignKey(rs, referenceIdSet, "PTRefFk");
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);
183 } catch (SQLException e
) {
184 throw new RuntimeException(e
);
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])){
198 makeSingleType(state
, name
, typeInfo
[0], typeInfo
[1], typeInfo
[2]);
204 private String
[] getTypeInfo(ResultSet rs
, int i
) throws SQLException
{
205 String
[] typeInfo
= new String
[3];
210 number
= String
.valueOf(i
);
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
);
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
);
226 handleSpecimenType(state
, name
, typeString
, typeCollectorString
, typeLocationString
);
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")){
238 String
[] splits
= typeLocationString
.split(";");
239 for (String split
: splits
){
240 List
<SpecimenTypeDesignation
> splitDesignations
= handleTypeLocationPart(state
, typeString
, typeCollectorString
, split
);
241 designations
.addAll(splitDesignations
);
244 if (designations
.size() == 0){
245 logger
.error(state
.getTaxonNumber() + " - No designations defined. TypeString: " + CdmUtils
.Nz(typeString
) + ", CollectorString: " + typeCollectorString
);
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);
255 DerivedUnit specimen
= designation
.getTypeSpecimen();
257 if (lastFacade
!= null){
258 lastFacade
.addDuplicate(specimen
);
262 lastFacade
= DerivedUnitFacade
.NewInstance(specimen
);
263 } catch (DerivedUnitFacadeNotSupportedException e
) {
264 throw new RuntimeException(e
);
268 lastFacade
.setLocality(typeString
);
269 makeTypeCollectorInfo(lastFacade
, typeCollectorString
);
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;
290 for (String split
: splits
){
291 split
= split
.trim();
292 if (StringUtils
.isBlank(split
)){
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
)){
300 lastDesignation
= makeSpecimenTypeCollection(lastDesignation
, split
, collectionPattern
, numberPattern
, addInfoPattern
);
301 }else if(split
.equalsIgnoreCase("not located")){
302 lastDesignation
= makeCachedSpecimenDesignation(split
);
304 logger
.error(state
.getTaxonNumber() + " - Unknown type location part: " + split
);
305 if (lastDesignation
== null){
306 lastDesignation
= makeCachedSpecimenDesignation(split
);
309 if (lastDesignation
!= null && ! result
.contains(lastDesignation
)){
310 result
.add(lastDesignation
);
311 }else if (lastDesignation
== null){
312 logger
.warn("Last Designation is null");
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
;
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
);
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
);
347 String strCollection
= matcher
.group();
348 Collection collection
= getCollection(strCollection
);
349 specimen
.setCollection(collection
);
350 collectionString
= collectionString
.substring(strCollection
.length()).trim();
354 Pattern numberPattern
= Pattern
.compile(strNumberPattern
);
355 matcher
= numberPattern
.matcher(collectionString
);
357 String strNumber
= matcher
.group();
358 collectionString
= collectionString
.substring(strNumber
.length()).trim();
359 if (StringUtils
.isNotBlank(strNumber
)){
360 specimen
.setCatalogNumber(strNumber
);
363 //throw new RuntimeException("numberString doesn't match: " + collectionString);
367 Pattern addInfoPattern
= Pattern
.compile(strAddInfoPattern
);
368 matcher
= addInfoPattern
.matcher(collectionString
);
370 String strAddInfo
= matcher
.group();
371 collectionString
= collectionString
.substring(strAddInfo
.length()).trim();
372 if (StringUtils
.isBlank(strAddInfo
)){
374 }else if (strAddInfo
.equals("!")){
375 //TODO add seen by author
376 }else if (strAddInfo
.equals("?")){
378 }else if (strAddInfo
.equals("+")){
382 //throw new RuntimeException("addInfoString doesn't match: " + collectionString);
384 if (StringUtils
.isNotBlank(collectionString
)){
385 logger
.error("Collection string is not empty: " + collectionString
);
392 private Collection
getCollection(String strCollection
) {
393 //TODO use BCI and deduplication
394 Collection result
= Collection
.NewInstance();
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();
419 logger
.error("Type Status not supported: " + type
);
420 throw new RuntimeException("Type Status not supported: " + type
);
422 if (designation
== null){
423 logger
.error("Designation is null");
425 designation
.setTypeStatus(status
);
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
);
436 if (StringUtils
.isNotBlank(typeLocation
)){
437 logger
.error(state
.getTaxonNumber() + " - Type location string for name type is not empty: " + typeLocation
);
439 NameTypeDesignation nameTypeDesignation
= NameTypeDesignation
.NewInstance();
440 NameTypeDesignationStatus status
= null;
441 if (StringUtils
.isBlank(typeString
)){
442 logger
.warn(state
.getTaxonNumber() + " - TypeString is empty");
444 if (typeString
.startsWith("None designated.")){
445 nameTypeDesignation
.setNotDesignated(true);
446 typeString
= typeString
.replaceFirst("None designated\\.", "").trim();
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
);
454 typeString
= handleDesignatedBy(nameTypeDesignation
, typeString
);
457 // String strSecondNamePattern = "([^\\(]*|\\(.*\\))+;.+"; //never ending story
458 String strSecondNamePattern
= ".+;.+";
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
);
469 firstName
= typeString
;
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());
479 if (! nameTypeName
.getRank().equals(Rank
.SPECIES())){
480 logger
.warn(state
.getTaxonNumber() + " - Name type is not of rank species: " + nameTypeName
.getTitleCache());
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());
488 if (! secondNameType
.getRank().equals(Rank
.SPECIES())){
489 logger
.error(state
.getTaxonNumber() + " - Second name type is not of rank species: " + secondNameType
.getTitleCache());
493 nameTypeDesignation
.setTypeStatus(status
);
494 name
.addTypeDesignation(nameTypeDesignation
, false);
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);
506 BotanicalName result
= (BotanicalName
)NonViralNameParserImpl
.NewInstance().parseFullName(strName
, NomenclaturalCode
.ICNAFP
, Rank
.SPECIES());
512 private BotanicalName
[] getNameTypeName(String strName
) {
513 //TODO implement get existing names
514 logger
.info("Not yet fully implemented");
516 BotanicalName
[] result
= new BotanicalName
[2];
517 if (strName
.endsWith(",")){
518 strName
= strName
.substring(0, strName
.length() -1);
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);
529 acceptedName
= acceptedName
.replaceFirst("=", "").trim();
530 result
[1] = (BotanicalName
)NonViralNameParserImpl
.NewInstance().parseFullName(acceptedName
, NomenclaturalCode
.ICNAFP
, null);
531 strName
= notAcceptedName
;
534 result
[0] = (BotanicalName
)NonViralNameParserImpl
.NewInstance().parseFullName(strName
, NomenclaturalCode
.ICNAFP
, Rank
.SPECIES());
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");
549 return splitDesignated
[0].trim();
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})\\)\\.?";
559 String strStandardPattern
= ".*" + strBracketPattern
;
560 // strStandardPattern = ".*";
561 if (Pattern
.matches(strStandardPattern
, citationString
)){
562 parseStandardPattern(typeDesignation
, result
, citationString
, strBracketPattern
);
564 logger
.error("Can't parse designation citation: " + citationString
);
565 result
.setTitleCache(citationString
);
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);
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
);
591 private void makeTypeCollectorInfo(DerivedUnitFacade specimen
, String collectorAndNumberString
) {
592 if (StringUtils
.isBlank(collectorAndNumberString
)){
595 String reNumber
= "(s\\.n\\.|\\d.*)";
596 Pattern reNumberPattern
= Pattern
.compile(reNumber
);
597 Matcher matcher
= reNumberPattern
.matcher(collectorAndNumberString
);
599 if ( matcher
.find()){
600 int numberStart
= matcher
.start();
601 String number
= collectorAndNumberString
.substring(numberStart
).trim();
602 if (numberStart
> 0){
603 numberStart
= numberStart
-1;
605 String collectorString
= collectorAndNumberString
.substring(0, numberStart
).trim();
606 specimen
.setFieldNumber(number
);
607 TeamOrPersonBase team
= getTeam(collectorString
);
608 specimen
.setCollector(team
);
611 logger
.warn("collector string did not match number pattern: " + collectorAndNumberString
);
617 private TeamOrPersonBase
getTeam(String teamString
) {
618 //TODO check existing team
619 TeamOrPersonBase result
= Team
.NewTitledInstance(teamString
, teamString
);
626 * for internal use only, used by MethodMapper
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");
636 String fascicle
= rs
.getString("Book / Journal fascicle");
637 String part
= rs
.getString("Book / Journal part");
638 String paperTitle
= rs
.getString("Book / Paper title");
640 String datePublishedString
= rs
.getString("Date published");
641 String referenceString
= referenceFullString
;
642 if (StringUtils
.isBlank(referenceString
)){
643 referenceString
= referenceAbbreviatedString
;
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;
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
;
667 name
.setNomenclaturalReference(reference
);
671 String details
= CdmUtils
.concat(", ", pages
, illustrations
);
672 details
= StringUtils
.isBlank(details
) ?
null : details
.trim();
673 name
.setNomenclaturalMicroReference(details
);
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
) {
683 logger
.warn(taxonNumber
+ " - Taxon has no reference");
689 * for internal use only, used by MethodMapper
692 private TaxonBase
mapNomRemarks(ResultSet rs
, CentralAfricaFernsImportState state
) throws Exception
{
694 String taxonNumber
= state
.getTaxonNumber();
695 String nomRemarksString
= rs
.getString("Nom remarks");
696 String taxonStatus
= rs
.getString("Current/Synonym");
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
);
704 } catch (Exception e
) {
710 private void parseNomRemark(CentralAfricaFernsImportState state
, INonViralName name
, String nomRemarksString
, String taxonStatus
, String taxonNumber
) {
712 if (nomRemarksString
.equalsIgnoreCase("comb. illeg.")){
713 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.COMBINATION_ILLEGITIMATE()));
715 // }else if (nomRemarksString.startsWith("comb. inval.")){
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()));
723 }else if (nomRemarksString
.matches("nom\\. cons(erv)?\\.")){
724 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.CONSERVED()));
726 }else if (nomRemarksString
.matches("nom\\. illeg(it)?\\.")){
727 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.ILLEGITIMATE()));
729 }else if (nomRemarksString
.matches("nom\\. inval(id)?\\.")){
730 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.INVALID()));
732 }else if (nomRemarksString
.matches("nom\\. nov\\.")){
733 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.NOVUM()));
735 }else if (nomRemarksString
.matches("nom\\. nud\\.")){
736 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.NUDUM()));
738 }else if (nomRemarksString
.matches("nom\\. superfl\\.")){
739 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.SUPERFLUOUS()));
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");
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
);
757 if (StringUtils
.isNotBlank(nomRemarksString
)){
758 ExtensionType extensionType
= getExtensionType(state
, CentralAfricaFernsTransformer
.uuidNomenclaturalRemarks
, "Nomenclatural remarks", "Nomenclatural remarks", null);
759 name
.addExtension(nomRemarksString
, extensionType
);
770 * @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet)
773 public TaxonBase
createObject(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
774 BotanicalName taxonName
= BotanicalName
.NewInstance(null);
775 Reference sec
= state
.getConfig().getSourceReference();
777 String taxonNumber
= rs
.getString("Taxon number");
778 state
.setTaxonNumber(taxonNumber
);
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");
798 String status
= rs
.getString("Current/Synonym");
800 TaxonBase taxon
= makeTaxon(taxonName
, sec
, taxonNumber
, status
);
802 // Integer parent3Rank = rs.getInt("parent3rank");
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();
811 lowestRank
= setLowestInfraSpecific(taxonName
, lowestRank
, subspeciesName
, varietyName
, subVariety
, formaName
,subFormaName
);
813 taxonName
.setRank(lowestRank
);
814 state
.setCurrentRank(taxonName
.getRank());
815 setAuthor(taxonName
, rs
, taxonNumber
, false);
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);
827 * Creates the taxon object depending on name, sec and status
834 private TaxonBase
makeTaxon(BotanicalName taxonName
, Reference sec
, String taxonNumber
, String status
) {
836 if ("c".equalsIgnoreCase(status
)|| "incertus".equalsIgnoreCase(status
) ){
837 taxon
= Taxon
.NewInstance(taxonName
, sec
);
838 if ("incertus".equalsIgnoreCase(status
)){
839 taxon
.setDoubtful(true);
841 }else if ("s".equalsIgnoreCase(status
)){
842 taxon
= Synonym
.NewInstance(taxonName
, sec
);
844 logger
.warn(taxonNumber
+ ": Status not given for taxon " );
845 taxon
= Taxon
.NewUnknownStatusInstance(taxonName
, sec
);
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
);
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();
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();
895 private Rank
setLowestUninomial(BotanicalName taxonName
, String orderName
, String subOrderName
, String familyName
, String subFamilyName
,
896 String tribusName
, String subTribusName
, String genusName
) {
898 if (StringUtils
.isNotBlank(genusName
)){
899 taxonName
.setGenusOrUninomial(genusName
);
901 }else if (StringUtils
.isNotBlank(subTribusName
)){
902 taxonName
.setGenusOrUninomial(subTribusName
);
903 return Rank
.SUBTRIBE();
904 }else if (StringUtils
.isNotBlank(tribusName
)){
905 taxonName
.setGenusOrUninomial(tribusName
);
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
);
926 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
929 protected boolean doCheck(CentralAfricaFernsImportState state
){
930 IOValidator
<CentralAfricaFernsImportState
> validator
= new CentralAfricaFernsTaxonImportValidator();
931 return validator
.validate(state
);
936 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
939 protected boolean isIgnore(CentralAfricaFernsImportState state
){
940 return ! state
.getConfig().isDoTaxa();