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
.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
;
76 public class CentralAfricaFernsTaxonImport
extends CentralAfricaFernsImportBase
<TaxonBase
> implements IMappingImport
<TaxonBase
, CentralAfricaFernsImportState
>{
77 private static final Logger logger
= Logger
.getLogger(CentralAfricaFernsTaxonImport
.class);
79 public static final UUID TNS_EXT_UUID
= UUID
.fromString("41cb0450-ac84-4d73-905e-9c7773c23b05");
82 private DbImportMapping mapping
;
84 //second path is not used anymore, there is now an ErmsTaxonRelationImport class instead
85 private boolean isSecondPath
= false;
87 private static final String pluralString
= "taxa";
88 private static final String dbTableName
= "[African pteridophytes]";
89 private static final Class cdmTargetClass
= TaxonBase
.class;
91 public CentralAfricaFernsTaxonImport(){
92 super(pluralString
, dbTableName
, cdmTargetClass
);
98 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getIdQuery()
101 protected String
getIdQuery() {
102 String strQuery
= " SELECT [Taxon number] FROM " + dbTableName
;
108 * @see eu.etaxonomy.cdm.io.eflora.centralAfrica.ferns.CentralAfricaFernsImportBase#getMapping()
110 protected DbImportMapping
getMapping() {
111 if (mapping
== null){
112 mapping
= new DbImportMapping();
114 mapping
.addMapper(DbImportObjectCreationMapper
.NewInstance(this, "Taxon number", TAXON_NAMESPACE
)); //id + tu_status
116 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapTypes", ResultSet
.class, CentralAfricaFernsImportState
.class));
117 mapping
.addMapper(DbImportAnnotationMapper
.NewInstance("Notes", AnnotationType
.EDITORIAL()));
119 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapReferences", ResultSet
.class, CentralAfricaFernsImportState
.class));
120 mapping
.addMapper(DbImportMethodMapper
.NewInstance(this, "mapNomRemarks", ResultSet
.class, CentralAfricaFernsImportState
.class));
122 mapping
.addMapper(DbImportExtensionMapper
.NewInstance("Illustrations - non-original", CentralAfricaFernsTransformer
.uuidIllustrationsNonOriginal
, "Illustrations - non-original", "Illustrations - non-original", null));
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));
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"));
130 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Basionym of", "Needs better understanding"));
131 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Synonym of", "Needs better understanding. Strange values like "));
134 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Chromosome number" , "Wrong data. Seems to be 'reference full'"));
136 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Book Publisher & Place" , "How to access the reference via String mapper?"));
138 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Reprint no" , "What's this?"));
139 mapping
.addMapper(DbNotYetImplementedMapper
.NewInstance("Date verified" , "Needed?"));
143 // UUID credibilityUuid = ErmsTransformer.uuidCredibility;
144 // mapping.addMapper(DbImportExtensionMapper.NewInstance("tu_credibility", credibilityUuid, "credibility", "credibility", "credibility")); //Werte: null, unknown, marked for deletion
147 // mapping.addMapper(DbIgnoreMapper.NewInstance("cache_citation", "citation cache not needed in PESI"));
149 //not yet implemented or ignore
150 // mapping.addMapper(DbNotYetImplementedMapper.NewInstance("tu_hidden", "Needs DbImportMarkerMapper implemented"));
157 * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getRecordQuery(eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportConfigurator)
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
;
171 * @see eu.etaxonomy.cdm.io.berlinModel.in.IPartitionedIO#getRelatedObjectsForPartition(java.sql.ResultSet)
173 public Map
<Object
, Map
<String
, ?
extends CdmBase
>> getRelatedObjectsForPartition(ResultSet rs
) {
177 Map
<Object
, Map
<String
, ?
extends CdmBase
>> result
= new HashMap
<Object
, Map
<String
, ?
extends CdmBase
>>();
180 Set
<String
> nameIdSet
= new HashSet
<String
>();
181 Set
<String
> referenceIdSet
= new HashSet
<String
>();
183 // handleForeignKey(rs, nameIdSet, "PTNameFk");
184 // handleForeignKey(rs, referenceIdSet, "PTRefFk");
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);
193 } catch (SQLException e
) {
194 throw new RuntimeException(e
);
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])){
208 makeSingleType(state
, name
, typeInfo
[0], typeInfo
[1], typeInfo
[2]);
214 private String
[] getTypeInfo(ResultSet rs
, int i
) throws SQLException
{
215 String
[] typeInfo
= new String
[3];
220 number
= String
.valueOf(i
);
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
);
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
);
236 handleSpecimenType(state
, name
, typeString
, typeCollectorString
, typeLocationString
);
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")){
248 String
[] splits
= typeLocationString
.split(";");
249 for (String split
: splits
){
250 List
<SpecimenTypeDesignation
> splitDesignations
= handleTypeLocationPart(state
, typeString
, typeCollectorString
, split
);
251 designations
.addAll(splitDesignations
);
254 if (designations
.size() == 0){
255 logger
.error(state
.getTaxonNumber() + " - No designations defined. TypeString: " + CdmUtils
.Nz(typeString
) + ", CollectorString: " + typeCollectorString
);
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);
265 DerivedUnitBase specimen
= designation
.getTypeSpecimen();
267 if (lastFacade
!= null){
268 lastFacade
.addDuplicate(specimen
);
272 lastFacade
= DerivedUnitFacade
.NewInstance(specimen
);
273 } catch (DerivedUnitFacadeNotSupportedException e
) {
274 throw new RuntimeException(e
);
278 lastFacade
.setLocality(typeString
);
279 makeTypeCollectorInfo(lastFacade
, typeCollectorString
);
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;
300 for (String split
: splits
){
301 split
= split
.trim();
302 if (StringUtils
.isBlank(split
)){
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
)){
310 lastDesignation
= makeSpecimenTypeCollection(lastDesignation
, split
, collectionPattern
, numberPattern
, addInfoPattern
);
311 }else if(split
.equalsIgnoreCase("not located")){
312 lastDesignation
= makeCachedSpecimenDesignation(split
);
314 logger
.error(state
.getTaxonNumber() + " - Unknown type location part: " + split
);
315 if (lastDesignation
== null){
316 lastDesignation
= makeCachedSpecimenDesignation(split
);
319 if (lastDesignation
!= null && ! result
.contains(lastDesignation
)){
320 result
.add(lastDesignation
);
321 }else if (lastDesignation
== null){
322 logger
.warn("Last Designation is null");
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
;
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
);
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
);
357 String strCollection
= matcher
.group();
358 Collection collection
= getCollection(strCollection
);
359 specimen
.setCollection(collection
);
360 collectionString
= collectionString
.substring(strCollection
.length()).trim();
364 Pattern numberPattern
= Pattern
.compile(strNumberPattern
);
365 matcher
= numberPattern
.matcher(collectionString
);
367 String strNumber
= matcher
.group();
368 collectionString
= collectionString
.substring(strNumber
.length()).trim();
369 if (StringUtils
.isNotBlank(strNumber
)){
370 specimen
.setCatalogNumber(strNumber
);
373 //throw new RuntimeException("numberString doesn't match: " + collectionString);
377 Pattern addInfoPattern
= Pattern
.compile(strAddInfoPattern
);
378 matcher
= addInfoPattern
.matcher(collectionString
);
380 String strAddInfo
= matcher
.group();
381 collectionString
= collectionString
.substring(strAddInfo
.length()).trim();
382 if (StringUtils
.isBlank(strAddInfo
)){
384 }else if (strAddInfo
.equals("!")){
385 //TODO add seen by author
386 }else if (strAddInfo
.equals("?")){
388 }else if (strAddInfo
.equals("+")){
392 //throw new RuntimeException("addInfoString doesn't match: " + collectionString);
394 if (StringUtils
.isNotBlank(collectionString
)){
395 logger
.error("Collection string is not empty: " + collectionString
);
402 private Collection
getCollection(String strCollection
) {
403 //TODO use BCI and deduplication
404 Collection result
= Collection
.NewInstance();
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();
429 logger
.error("Type Status not supported: " + type
);
430 throw new RuntimeException("Type Status not supported: " + type
);
432 if (designation
== null){
433 logger
.error("Designation is null");
435 designation
.setTypeStatus(status
);
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
);
446 if (StringUtils
.isNotBlank(typeLocation
)){
447 logger
.error(state
.getTaxonNumber() + " - Type location string for name type is not empty: " + typeLocation
);
449 NameTypeDesignation nameTypeDesignation
= NameTypeDesignation
.NewInstance();
450 NameTypeDesignationStatus status
= null;
451 if (StringUtils
.isBlank(typeString
)){
452 logger
.warn(state
.getTaxonNumber() + " - TypeString is empty");
454 if (typeString
.startsWith("None designated.")){
455 nameTypeDesignation
.setNotDesignated(true);
456 typeString
= typeString
.replaceFirst("None designated\\.", "").trim();
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
);
464 typeString
= handleDesignatedBy(nameTypeDesignation
, typeString
);
467 // String strSecondNamePattern = "([^\\(]*|\\(.*\\))+;.+"; //never ending story
468 String strSecondNamePattern
= ".+;.+";
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
);
479 firstName
= typeString
;
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());
489 if (! nameTypeName
.getRank().equals(Rank
.SPECIES())){
490 logger
.warn(state
.getTaxonNumber() + " - Name type is not of rank species: " + nameTypeName
.getTitleCache());
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());
498 if (! secondNameType
.getRank().equals(Rank
.SPECIES())){
499 logger
.error(state
.getTaxonNumber() + " - Second name type is not of rank species: " + secondNameType
.getTitleCache());
503 nameTypeDesignation
.setTypeStatus(status
);
504 name
.addTypeDesignation(nameTypeDesignation
, false);
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);
516 BotanicalName result
= (BotanicalName
)NonViralNameParserImpl
.NewInstance().parseFullName(strName
, NomenclaturalCode
.ICBN
, Rank
.SPECIES());
522 private BotanicalName
[] getNameTypeName(String strName
) {
523 //TODO implement get existing names
524 logger
.info("Not yet fully implemented");
526 BotanicalName
[] result
= new BotanicalName
[2];
527 if (strName
.endsWith(",")){
528 strName
= strName
.substring(0, strName
.length() -1);
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);
539 acceptedName
= acceptedName
.replaceFirst("=", "").trim();
540 result
[1] = (BotanicalName
)NonViralNameParserImpl
.NewInstance().parseFullName(acceptedName
, NomenclaturalCode
.ICBN
, null);
541 strName
= notAcceptedName
;
544 result
[0] = (BotanicalName
)NonViralNameParserImpl
.NewInstance().parseFullName(strName
, NomenclaturalCode
.ICBN
, Rank
.SPECIES());
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");
559 return splitDesignated
[0].trim();
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})\\)\\.?";
569 String strStandardPattern
= ".*" + strBracketPattern
;
570 // strStandardPattern = ".*";
571 if (Pattern
.matches(strStandardPattern
, citationString
)){
572 parseStandardPattern(typeDesignation
, result
, citationString
, strBracketPattern
);
574 logger
.error("Can't parse designation citation: " + citationString
);
575 result
.setTitleCache(citationString
);
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);
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
);
601 private void makeTypeCollectorInfo(DerivedUnitFacade specimen
, String collectorAndNumberString
) {
602 if (StringUtils
.isBlank(collectorAndNumberString
)){
605 String reNumber
= "(s\\.n\\.|\\d.*)";
606 Pattern reNumberPattern
= Pattern
.compile(reNumber
);
607 Matcher matcher
= reNumberPattern
.matcher(collectorAndNumberString
);
609 if ( matcher
.find()){
610 int numberStart
= matcher
.start();
611 String number
= collectorAndNumberString
.substring(numberStart
).trim();
612 if (numberStart
> 0){
613 numberStart
= numberStart
-1;
615 String collectorString
= collectorAndNumberString
.substring(0, numberStart
).trim();
616 specimen
.setFieldNumber(number
);
617 TeamOrPersonBase team
= getTeam(collectorString
);
618 specimen
.setCollector(team
);
621 logger
.warn("collector string did not match number pattern: " + collectorAndNumberString
);
627 private TeamOrPersonBase
getTeam(String teamString
) {
628 //TODO check existing team
629 TeamOrPersonBase result
= Team
.NewTitledInstance(teamString
, teamString
);
636 * for internal use only, used by MethodMapper
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");
646 String fascicle
= rs
.getString("Book / Journal fascicle");
647 String part
= rs
.getString("Book / Journal part");
648 String paperTitle
= rs
.getString("Book / Paper title");
650 String datePublishedString
= rs
.getString("Date published");
651 String referenceString
= referenceFullString
;
652 if (StringUtils
.isBlank(referenceString
)){
653 referenceString
= referenceAbbreviatedString
;
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;
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
;
677 name
.setNomenclaturalReference(reference
);
681 String details
= CdmUtils
.concat(", ", pages
, illustrations
);
682 details
= StringUtils
.isBlank(details
) ?
null : details
.trim();
683 name
.setNomenclaturalMicroReference(details
);
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
) {
693 logger
.warn(taxonNumber
+ " - Taxon has no reference");
699 * for internal use only, used by MethodMapper
702 private TaxonBase
mapNomRemarks(ResultSet rs
, CentralAfricaFernsImportState state
) throws Exception
{
704 String taxonNumber
= state
.getTaxonNumber();
705 String nomRemarksString
= rs
.getString("Nom remarks");
706 String taxonStatus
= rs
.getString("Current/Synonym");
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
);
714 } catch (Exception e
) {
720 private void parseNomRemark(CentralAfricaFernsImportState state
, NonViralName name
, String nomRemarksString
, String taxonStatus
, String taxonNumber
) {
722 if (nomRemarksString
.equalsIgnoreCase("comb. illeg.")){
723 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.COMBINATION_ILLEGITIMATE()));
725 // }else if (nomRemarksString.startsWith("comb. inval.")){
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()));
733 }else if (nomRemarksString
.matches("nom\\. cons(erv)?\\.")){
734 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.CONSERVED()));
736 }else if (nomRemarksString
.matches("nom\\. illeg(it)?\\.")){
737 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.ILLEGITIMATE()));
739 }else if (nomRemarksString
.matches("nom\\. inval(id)?\\.")){
740 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.INVALID()));
742 }else if (nomRemarksString
.matches("nom\\. nov\\.")){
743 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.NOVUM()));
745 }else if (nomRemarksString
.matches("nom\\. nud\\.")){
746 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.NUDUM()));
748 }else if (nomRemarksString
.matches("nom\\. superfl\\.")){
749 name
.addStatus(NomenclaturalStatus
.NewInstance(NomenclaturalStatusType
.SUPERFLUOUS()));
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");
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
);
767 if (StringUtils
.isNotBlank(nomRemarksString
)){
768 ExtensionType extensionType
= getExtensionType(state
, CentralAfricaFernsTransformer
.uuidNomenclaturalRemarks
, "Nomenclatural remarks", "Nomenclatural remarks", null);
769 name
.addExtension(nomRemarksString
, extensionType
);
780 * @see eu.etaxonomy.cdm.io.common.mapping.IMappingImport#createObject(java.sql.ResultSet)
782 public TaxonBase
createObject(ResultSet rs
, CentralAfricaFernsImportState state
) throws SQLException
{
783 BotanicalName taxonName
= BotanicalName
.NewInstance(null);
784 Reference sec
= state
.getConfig().getSourceReference();
786 String taxonNumber
= rs
.getString("Taxon number");
787 state
.setTaxonNumber(taxonNumber
);
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");
807 String status
= rs
.getString("Current/Synonym");
809 TaxonBase taxon
= makeTaxon(taxonName
, sec
, taxonNumber
, status
);
811 // Integer parent3Rank = rs.getInt("parent3rank");
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();
820 lowestRank
= setLowestInfraSpecific(taxonName
, lowestRank
, subspeciesName
, varietyName
, subVariety
, formaName
,subFormaName
);
822 taxonName
.setRank(lowestRank
);
823 state
.setCurrentRank(taxonName
.getRank());
824 setAuthor(taxonName
, rs
, taxonNumber
, false);
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);
836 * Creates the taxon object depending on name, sec and status
843 private TaxonBase
makeTaxon(BotanicalName taxonName
, Reference sec
, String taxonNumber
, String status
) {
845 if ("c".equalsIgnoreCase(status
)|| "incertus".equalsIgnoreCase(status
) ){
846 taxon
= Taxon
.NewInstance(taxonName
, sec
);
847 if ("incertus".equalsIgnoreCase(status
)){
848 taxon
.setDoubtful(true);
850 }else if ("s".equalsIgnoreCase(status
)){
851 taxon
= Synonym
.NewInstance(taxonName
, sec
);
853 logger
.warn(taxonNumber
+ ": Status not given for taxon " );
854 taxon
= Taxon
.NewUnknownStatusInstance(taxonName
, sec
);
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
);
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();
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();
904 private Rank
setLowestUninomial(BotanicalName taxonName
, String orderName
, String subOrderName
, String familyName
, String subFamilyName
,
905 String tribusName
, String subTribusName
, String genusName
) {
907 if (StringUtils
.isNotBlank(genusName
)){
908 taxonName
.setGenusOrUninomial(genusName
);
910 }else if (StringUtils
.isNotBlank(subTribusName
)){
911 taxonName
.setGenusOrUninomial(subTribusName
);
912 return Rank
.SUBTRIBE();
913 }else if (StringUtils
.isNotBlank(tribusName
)){
914 taxonName
.setGenusOrUninomial(tribusName
);
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
);
935 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#doCheck(eu.etaxonomy.cdm.io.common.IoStateBase)
938 protected boolean doCheck(CentralAfricaFernsImportState state
){
939 IOValidator
<CentralAfricaFernsImportState
> validator
= new CentralAfricaFernsTaxonImportValidator();
940 return validator
.validate(state
);
945 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IoStateBase)
948 protected boolean isIgnore(CentralAfricaFernsImportState state
){
949 return ! state
.getConfig().isDoTaxa();