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.
9 package eu
.etaxonomy
.cdm
.io
.redlist
.gefaesspflanzen
;
11 import java
.sql
.ResultSet
;
12 import java
.sql
.SQLException
;
13 import java
.util
.HashMap
;
14 import java
.util
.HashSet
;
17 import java
.util
.regex
.Matcher
;
18 import java
.util
.regex
.Pattern
;
20 import org
.apache
.logging
.log4j
.LogManager
;
21 import org
.apache
.logging
.log4j
.Logger
;
22 import org
.springframework
.stereotype
.Component
;
24 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
25 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
26 import eu
.etaxonomy
.cdm
.io
.common
.DbImportBase
;
27 import eu
.etaxonomy
.cdm
.io
.common
.IPartitionedIO
;
28 import eu
.etaxonomy
.cdm
.io
.common
.ImportHelper
;
29 import eu
.etaxonomy
.cdm
.io
.common
.ResultSetPartitioner
;
30 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
31 import eu
.etaxonomy
.cdm
.model
.agent
.AgentBase
;
32 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
33 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
34 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
35 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
36 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
37 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
38 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
39 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
40 import eu
.etaxonomy
.cdm
.model
.name
.ICultivarPlantName
;
41 import eu
.etaxonomy
.cdm
.model
.name
.INonViralName
;
42 import eu
.etaxonomy
.cdm
.model
.name
.ITaxonNameBase
;
43 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalCode
;
44 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatus
;
45 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
46 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
47 import eu
.etaxonomy
.cdm
.model
.name
.RankClass
;
48 import eu
.etaxonomy
.cdm
.model
.name
.TaxonName
;
49 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
50 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
51 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
52 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
53 import eu
.etaxonomy
.cdm
.model
.term
.OrderedTermVocabulary
;
54 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
61 @SuppressWarnings("serial")
62 public class RedListGefaesspflanzenImportNames
extends DbImportBase
<RedListGefaesspflanzenImportState
, RedListGefaesspflanzenImportConfigurator
> {
64 private static final Logger logger
= LogManager
.getLogger();
66 private static final String tableName
= "Rote Liste Gefäßpflanzen";
68 private static final String pluralString
= "names";
70 private static final boolean STRICT_TITLE_CHECK
= false;
72 private ExtensionType extensionTypeFlor
;
74 private ExtensionType extensionTypeAtlasIdx
;
76 private ExtensionType extensionTypeKart
;
78 private ExtensionType extensionTypeRl2015
;
80 private ExtensionType extensionTypeEhrd
;
82 private ExtensionType extensionTypeWissk
;
84 public RedListGefaesspflanzenImportNames() {
85 super(tableName
, pluralString
);
89 protected String
getIdQuery(RedListGefaesspflanzenImportState state
) {
90 return "SELECT SEQNUM "
91 + "FROM V_TAXATLAS_D20_EXPORT t "
96 protected String
getRecordQuery(RedListGefaesspflanzenImportConfigurator config
) {
97 String result
= " SELECT * "
98 + " FROM V_TAXATLAS_D20_EXPORT t "
99 + " WHERE t.SEQNUM IN (@IDSET)";
100 result
= result
.replace("@IDSET", IPartitionedIO
.ID_LIST_TOKEN
);
105 protected void doInvoke(RedListGefaesspflanzenImportState state
) {
106 makeExtensionTypes();
107 super.doInvoke(state
);
111 private void makeExtensionTypes() {
112 extensionTypeFlor
= ExtensionType
.NewInstance(RedListUtil
.FLOR
, RedListUtil
.FLOR
, "");
113 extensionTypeAtlasIdx
= ExtensionType
.NewInstance(RedListUtil
.ATLAS_IDX
, RedListUtil
.ATLAS_IDX
, "");
114 extensionTypeKart
= ExtensionType
.NewInstance(RedListUtil
.KART
, RedListUtil
.KART
, "");
115 extensionTypeRl2015
= ExtensionType
.NewInstance(RedListUtil
.RL2015
, RedListUtil
.RL2015
, "");
116 extensionTypeEhrd
= ExtensionType
.NewInstance(RedListUtil
.EHRD
, RedListUtil
.EHRD
, "");
117 extensionTypeWissk
= ExtensionType
.NewInstance(RedListUtil
.WISSK
, RedListUtil
.WISSK
, "");
118 getTermService().saveOrUpdate(extensionTypeFlor
);
119 getTermService().saveOrUpdate(extensionTypeAtlasIdx
);
120 getTermService().saveOrUpdate(extensionTypeKart
);
121 getTermService().saveOrUpdate(extensionTypeRl2015
);
122 getTermService().saveOrUpdate(extensionTypeEhrd
);
123 getTermService().saveOrUpdate(extensionTypeWissk
);
127 public boolean doPartition(@SuppressWarnings("rawtypes") ResultSetPartitioner partitioner
, RedListGefaesspflanzenImportState state
) {
128 ResultSet rs
= partitioner
.getResultSet();
129 Set
<ITaxonNameBase
> namesToSave
= new HashSet
<>();
130 Set
<TaxonBase
> taxaToSave
= new HashSet
<>();
133 makeSingleNameAndTaxon(state
, rs
, namesToSave
, taxaToSave
);
136 } catch (SQLException e
) {
140 getNameService().saveOrUpdate(TaxonName
.castAndDeproxy(namesToSave
));
141 getTaxonService().saveOrUpdate(taxaToSave
);
145 private void makeSingleNameAndTaxon(RedListGefaesspflanzenImportState state
, ResultSet rs
, Set
<ITaxonNameBase
> namesToSave
, Set
<TaxonBase
> taxaToSave
)
146 throws SQLException
{
147 long id
= rs
.getLong(RedListUtil
.NAMNR
);
148 String relationE
= rs
.getString(RedListUtil
.E
);
149 String relationW
= rs
.getString(RedListUtil
.W
);
150 String relationK
= rs
.getString(RedListUtil
.K
);
151 String relationAW
= rs
.getString(RedListUtil
.AW
);
152 String relationAO
= rs
.getString(RedListUtil
.AO
);
153 String relationR
= rs
.getString(RedListUtil
.R
);
154 String relationO
= rs
.getString(RedListUtil
.O
);
155 String relationS
= rs
.getString(RedListUtil
.S
);
158 INonViralName name
= importName(state
, rs
, namesToSave
);
162 importAuthors(state
, rs
, name
);
165 TaxonBase
<?
> taxonBase
= importTaxon(rs
, name
, state
);
167 RedListUtil
.logMessage(id
, "!SERIOUS ERROR! Taxon for name "+name
+" could not be created!", logger
);
171 //---CONCEPT RELATIONSHIPS---
172 //E, W, K, AW, AO, R, O, S
173 cloneTaxon(taxonBase
, relationE
, RedListUtil
.CLASSIFICATION_NAMESPACE_E
, taxaToSave
, id
, state
);
174 cloneTaxon(taxonBase
, relationW
, RedListUtil
.CLASSIFICATION_NAMESPACE_W
, taxaToSave
, id
, state
);
175 cloneTaxon(taxonBase
, relationK
, RedListUtil
.CLASSIFICATION_NAMESPACE_K
, taxaToSave
, id
, state
);
176 cloneTaxon(taxonBase
, relationAW
, RedListUtil
.CLASSIFICATION_NAMESPACE_AW
, taxaToSave
, id
, state
);
177 cloneTaxon(taxonBase
, relationAO
, RedListUtil
.CLASSIFICATION_NAMESPACE_AO
, taxaToSave
, id
, state
);
178 cloneTaxon(taxonBase
, relationR
, RedListUtil
.CLASSIFICATION_NAMESPACE_R
, taxaToSave
, id
, state
);
179 cloneTaxon(taxonBase
, relationO
, RedListUtil
.CLASSIFICATION_NAMESPACE_O
, taxaToSave
, id
, state
);
180 cloneTaxon(taxonBase
, relationS
, RedListUtil
.CLASSIFICATION_NAMESPACE_S
, taxaToSave
, id
, state
);
182 //NOTE: the source has to be added after cloning or otherwise the clone would also get the source
183 ImportHelper
.setOriginalSource(taxonBase
, state
.getTransactionalSourceReference(), id
, RedListUtil
.TAXON_GESAMTLISTE_NAMESPACE
);
184 taxaToSave
.add(taxonBase
);
187 private void cloneTaxon(final TaxonBase
<?
> gesamtListeTaxon
, String relationString
, String sourceNameSpace
, Set
<TaxonBase
> taxaToSave
, long id
, RedListGefaesspflanzenImportState state
){
188 if(isNotBlank(relationString
) && !relationString
.equals(".")){
189 Taxon clonedTaxon
= null;
191 if(gesamtListeTaxon
.isInstanceOf(Taxon
.class)){
192 clonedTaxon
= HibernateProxyHelper
.deproxy(gesamtListeTaxon
.clone(), Taxon
.class);
194 else if(gesamtListeTaxon
.isInstanceOf(Synonym
.class)){
195 clonedTaxon
= Taxon
.NewInstance(gesamtListeTaxon
.getName(), gesamtListeTaxon
.getSec());
198 RedListUtil
.logMessage(id
, "Taxon base "+gesamtListeTaxon
+" is neither taxon nor synonym! Taxon could not be cloned", logger
);
201 ImportHelper
.setOriginalSource(clonedTaxon
, state
.getTransactionalSourceReference(), id
, sourceNameSpace
);
202 taxaToSave
.add(clonedTaxon
);
206 private TaxonBase
<?
> importTaxon(ResultSet rs
, INonViralName name
, RedListGefaesspflanzenImportState state
) throws SQLException
{
208 long id
= rs
.getLong(RedListUtil
.NAMNR
);
209 String taxNameString
= rs
.getString(RedListUtil
.TAXNAME
);
210 String epi1String
= rs
.getString(RedListUtil
.EPI1
);
211 String epi2String
= rs
.getString(RedListUtil
.EPI2
);
212 String epi3String
= rs
.getString(RedListUtil
.EPI3
);
213 String gueltString
= rs
.getString(RedListUtil
.GUELT
);
214 String trivialString
= rs
.getString(RedListUtil
.TRIVIAL
);
215 String authorBasiString
= rs
.getString(RedListUtil
.AUTOR_BASI
);
216 String hybString
= rs
.getString(RedListUtil
.HYB
);
217 String florString
= rs
.getString(RedListUtil
.FLOR
);
218 String atlasIdxString
= rs
.getString(RedListUtil
.ATLAS_IDX
);
219 String kartString
= rs
.getString(RedListUtil
.KART
);
220 String rl2015String
= rs
.getString(RedListUtil
.RL2015
);
221 String ehrdString
= rs
.getString(RedListUtil
.EHRD
);
222 String wisskString
= rs
.getString(RedListUtil
.WISSK
);
224 TaxonBase
<?
> taxonBase
= null;
225 if(authorBasiString
.trim().contains(RedListUtil
.AUCT
)){
226 taxonBase
= Taxon
.NewInstance(name
, null);
227 taxonBase
.setAppendedPhrase(RedListUtil
.AUCT
);
229 else if(gueltString
.equals(RedListUtil
.GUELT_ACCEPTED_TAXON
)){
230 taxonBase
= Taxon
.NewInstance(name
, null);
232 else if(gueltString
.equals(RedListUtil
.GUELT_SYNONYM
) || gueltString
.equals(RedListUtil
.GUELT_BASIONYM
)){
233 taxonBase
= Synonym
.NewInstance(name
, null);
236 RedListUtil
.logMessage(id
, "Taxon was not created!! Unknown value for "+RedListUtil
.GUELT
+"!", logger
);
241 if(taxonBase
.isInstanceOf(Taxon
.class) && trivialString
!=null){
242 Taxon taxon
= HibernateProxyHelper
.deproxy(taxonBase
, Taxon
.class);
243 TaxonDescription description
= TaxonDescription
.NewInstance(taxon
);
244 description
.addElement(CommonTaxonName
.NewInstance(trivialString
, Language
.GERMAN()));
248 taxonBase
.addExtension(florString
, extensionTypeFlor
);
249 taxonBase
.addExtension(atlasIdxString
, extensionTypeAtlasIdx
);
250 taxonBase
.addExtension(kartString
, extensionTypeKart
);
251 taxonBase
.addExtension(rl2015String
, extensionTypeRl2015
);
252 taxonBase
.addExtension(ehrdString
, extensionTypeEhrd
);
253 taxonBase
.addExtension(wisskString
, extensionTypeWissk
);
255 //check taxon name consistency
256 checkTaxonConsistency(id
, taxNameString
, hybString
, epi1String
, epi2String
, epi3String
, taxonBase
, state
);
260 private void importAuthors(RedListGefaesspflanzenImportState state
, ResultSet rs
, INonViralName name
) throws SQLException
{
262 long id
= rs
.getLong(RedListUtil
.NAMNR
);
263 String nomZusatzString
= rs
.getString(RedListUtil
.NOM_ZUSATZ
);
264 String taxZusatzString
= rs
.getString(RedListUtil
.TAX_ZUSATZ
);
265 String zusatzString
= rs
.getString(RedListUtil
.ZUSATZ
);
266 String authorKombString
= rs
.getString(RedListUtil
.AUTOR_KOMB
);
267 String authorBasiString
= rs
.getString(RedListUtil
.AUTOR_BASI
);
268 String hybString
= rs
.getString(RedListUtil
.HYB
);
271 if(authorKombString
.contains(RedListUtil
.EX
)){
272 // multiple ex authors will be reduced to only the last one
273 // e.g. Almq. ex Sternström ex Dahlst. -> Almq. ex Dahlst.
274 //first author is ex combination author
275 String exAuthorString
= RedListUtil
.getExAuthorOfExAuthorshipString(authorKombString
);
276 TeamOrPersonBase
<?
> exAuthor
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, exAuthorString
);
277 name
.setExCombinationAuthorship(exAuthor
);
278 //the last author is the combination author
279 String authorString
= RedListUtil
.getAuthorOfExAuthorshipString(authorKombString
);
280 TeamOrPersonBase
<?
> combAuthor
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, authorString
);
281 name
.setCombinationAuthorship(combAuthor
);
283 else if(authorKombString
.trim().contains(RedListUtil
.AUCT
)){
284 RedListUtil
.logMessage(id
, "AUCT information in "+RedListUtil
.AUTOR_KOMB
+" column", logger
);
286 else if(CdmUtils
.isNotBlank(authorKombString
)){
287 TeamOrPersonBase
<?
> authorKomb
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, authorKombString
);
288 name
.setCombinationAuthorship(authorKomb
);
291 if(authorBasiString
.contains(RedListUtil
.EX
)){
292 TeamOrPersonBase
<?
> authorExBasi
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, RedListUtil
.getExAuthorOfExAuthorshipString(authorBasiString
));
293 if(CdmUtils
.isBlank(authorKombString
)){
294 name
.setExCombinationAuthorship(authorExBasi
);
297 name
.setExBasionymAuthorship(authorExBasi
);
299 TeamOrPersonBase
<?
> authorBasi
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, RedListUtil
.getAuthorOfExAuthorshipString(authorBasiString
));
300 if(CdmUtils
.isBlank(authorKombString
)){
301 name
.setCombinationAuthorship(authorBasi
);
304 name
.setBasionymAuthorship(authorBasi
);
307 else if(CdmUtils
.isNotBlank(authorBasiString
)){
308 //this seems to be a convention in the source database: When there is only a single author then only the "AUTOR_BASI" column is used
309 TeamOrPersonBase
<?
> authorBasi
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, authorBasiString
);
310 if(CdmUtils
.isBlank(authorKombString
)){
311 name
.setCombinationAuthorship(authorBasi
);
314 name
.setBasionymAuthorship(authorBasi
);
318 //check authorship consistency
319 String authorString
= rs
.getString(RedListUtil
.AUTOR
);
320 checkNameConsistency(id
, nomZusatzString
, taxZusatzString
, zusatzString
, authorString
, hybString
, name
);
323 private INonViralName
importName(RedListGefaesspflanzenImportState state
, ResultSet rs
, Set
<ITaxonNameBase
> namesToSave
) throws SQLException
{
325 long id
= rs
.getLong(RedListUtil
.NAMNR
);
326 String taxNameString
= rs
.getString(RedListUtil
.TAXNAME
);
327 String rangString
= rs
.getString(RedListUtil
.RANG
);
328 String ep1String
= rs
.getString(RedListUtil
.EPI1
);
329 String ep2String
= rs
.getString(RedListUtil
.EPI2
);
330 String ep3String
= rs
.getString(RedListUtil
.EPI3
);
331 String nomZusatzString
= rs
.getString(RedListUtil
.NOM_ZUSATZ
);
332 String hybString
= rs
.getString(RedListUtil
.HYB
);
333 String formelString
= rs
.getString(RedListUtil
.FORMEL
);
335 if(CdmUtils
.isBlank(taxNameString
) && CdmUtils
.isBlank(ep1String
)){
336 RedListUtil
.logMessage(id
, "No name found!", logger
);
339 INonViralName name
= null;
340 Rank rank
= makeRank(id
, state
, rangString
, CdmUtils
.isNotBlank(ep3String
));
342 if(rank
!= null && rank
.equals(Rank
.CULTIVAR())){
343 ICultivarPlantName cultivar
= TaxonNameFactory
.NewCultivarInstance(rank
);
344 cultivar
.setGenusOrUninomial(ep1String
);
345 cultivar
.setSpecificEpithet(ep2String
);
346 cultivar
.setCultivarEpithet(ep3String
);
351 name
= TaxonNameFactory
.NewBotanicalInstance(rank
);
353 //ep1 should always be present
354 if(CdmUtils
.isBlank(ep1String
)){
355 RedListUtil
.logMessage(id
, RedListUtil
.EPI1
+" is empty!", logger
);
357 name
.setGenusOrUninomial(ep1String
);
358 if(CdmUtils
.isNotBlank(ep2String
)){
359 if(rank
!=null && rank
.isInfraGenericButNotSpeciesGroup()){
360 name
.setInfraGenericEpithet(ep2String
);
363 name
.setSpecificEpithet(ep2String
);
366 if(CdmUtils
.isNotBlank(ep3String
)){
367 name
.setInfraSpecificEpithet(ep3String
);
371 //nomenclatural status
372 if(CdmUtils
.isNotBlank(nomZusatzString
)){
373 NomenclaturalStatusType statusType
= makeNomenclaturalStatus(id
, state
, nomZusatzString
);
374 if(statusType
!=null){
375 NomenclaturalStatus status
= NomenclaturalStatus
.NewInstance(statusType
);
376 //special case for invalid names where the DB entry contains
377 //additional information in brackets e.g. "nom. inval. (sine basion.)"
378 if(statusType
.equals(NomenclaturalStatusType
.INVALID()) || statusType
.equals(NomenclaturalStatusType
.REJECTED()) ){
379 Pattern pattern
= Pattern
.compile("\\((.*?)\\)");
380 Matcher matcher
= pattern
.matcher(nomZusatzString
);
382 status
.setRuleConsidered(matcher
.group(1));
385 name
.addStatus(status
);
389 if(CdmUtils
.isNotBlank(hybString
)){
390 //more than two hybrids not yet handled by name parser
391 //TODO: use parser when implemented to fully support hybrids
392 if(taxNameString
.split(RedListUtil
.HYB_SIGN
).length
>2){
393 name
= TaxonNameFactory
.NewBotanicalInstance(rank
);
394 name
.setTitleCache(taxNameString
, true);
396 else if(hybString
.equals(RedListUtil
.HYB_X
)){
397 name
.setBinomHybrid(true);
399 else if(hybString
.equals(RedListUtil
.HYB_G
)){
400 name
.setMonomHybrid(true);
402 else if(hybString
.equals(RedListUtil
.HYB_XF
) || hybString
.equals(RedListUtil
.HYB_XU
)){
403 name
.setHybridFormula(true);
404 String fullFormula
= buildHybridFormula(ep1String
, ep2String
, ep3String
, rank
);
405 name
= NonViralNameParserImpl
.NewInstance().parseFullName(fullFormula
, NomenclaturalCode
.ICNAFP
, rank
);
407 else if(hybString
.equals(RedListUtil
.HYB_N
)){
408 name
= NonViralNameParserImpl
.NewInstance().parseFullName(taxNameString
, NomenclaturalCode
.ICNAFP
, rank
);
410 else if(hybString
.equals(RedListUtil
.HYB_GF
)){
411 if(ep1String
.contains(RedListUtil
.HYB_SIGN
)){
412 name
= NonViralNameParserImpl
.NewInstance().parseFullName(ep1String
, NomenclaturalCode
.ICNAFP
, rank
);
415 RedListUtil
.logMessage(id
, "HYB is "+hybString
+" but "+RedListUtil
.HYB
+" does not contain "+RedListUtil
.HYB_SIGN
, logger
);
418 else if(hybString
.equals(RedListUtil
.HYB_XS
)){
422 logger
.error("HYB value "+hybString
+" not yet handled");
424 //save hybrid formula
425 if(CdmUtils
.isNotBlank(formelString
)){
426 Annotation annotation
= Annotation
.NewDefaultLanguageInstance(formelString
);
427 annotation
.setAnnotationType(AnnotationType
.INTERNAL());
428 name
.addAnnotation(annotation
);
434 ImportHelper
.setOriginalSource(name
, state
.getTransactionalSourceReference(), id
, RedListUtil
.NAME_NAMESPACE
);
436 namesToSave
.add(name
);
440 private String
buildHybridFormula(String ep1String
, String ep2String
, String ep3String
, Rank rank
) {
441 String fullFormula
= null;
442 if(ep1String
.contains(RedListUtil
.HYB_SIGN
)){
443 fullFormula
= ep1String
;
445 else if(ep2String
.contains(RedListUtil
.HYB_SIGN
)){
446 String
[] split
= ep2String
.split(RedListUtil
.HYB_SIGN
);
447 String hybridFormula1
= ep1String
+" "+split
[0].trim();
448 String hybridFormula2
= ep1String
+" "+split
[1].trim();
449 //check if the genus is mentioned in EP2 or not
450 String
[] secondHybrid
= split
[1].trim().split(" ");
451 //check if the genus is abbreviated like e.g. Centaurea jacea × C. decipiens
452 if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z]\\.")){
453 hybridFormula2
= ep1String
+" "+split
[1].trim().substring(3);
455 else if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z].*")){
456 hybridFormula2
= split
[1].trim();
458 if(CdmUtils
.isNotBlank(ep3String
)){
459 hybridFormula1
+= " "+rank
.getAbbreviation()+" "+ep3String
;
460 hybridFormula2
+= " "+rank
.getAbbreviation()+" "+ep3String
;
462 fullFormula
= hybridFormula1
+" "+RedListUtil
.HYB_SIGN
+" "+hybridFormula2
;
464 else if(ep3String
.contains(RedListUtil
.HYB_SIGN
)){
465 String
[] split
= ep3String
.split(RedListUtil
.HYB_SIGN
);
466 String hybridFormula1
= ep1String
+" "+ep2String
+" "+rank
.getAbbreviation()+" "+split
[0].trim();
467 String hybridFormula2
= ep1String
+" "+ep2String
+" "+rank
.getAbbreviation()+" "+split
[1].trim();
468 //check if the genus is mentioned in EP3 or not
469 String
[] secondHybrid
= split
[1].trim().split(" ");
470 //check if the genus is abbreviated like e.g. Centaurea jacea jacea × C. jacea subsp. decipiens
471 if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z]\\.")){
472 hybridFormula2
= ep1String
+" "+split
[1].trim().substring(3);
474 else if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z].*")){
475 hybridFormula2
= split
[1].trim();
477 fullFormula
= hybridFormula1
+" "+RedListUtil
.HYB_SIGN
+" "+hybridFormula2
;
482 private void checkNameConsistency(long id
, String nomZusatzString
, String taxZusatzString
,
483 String zusatzString
, String authorString
, String hybString
, INonViralName name
) {
484 String authorshipCache
= name
.getAuthorshipCache();
485 //FIXME: remove split length check when name parser can parse multiple hybrid parents
486 if(hybString
.equals(RedListUtil
.HYB_XF
) && name
.getTitleCache().split(RedListUtil
.HYB_SIGN
).length
==2){
487 if(name
.getHybridChildRelations().isEmpty()){
488 RedListUtil
.logMessage(id
, "Hybrid formula but no hybrid child relations: "+name
.getTitleCache(), logger
);
494 if(CdmUtils
.isNotBlank(zusatzString
)){
495 authorString
= authorString
.replace(", "+zusatzString
, "");
497 if(CdmUtils
.isNotBlank(nomZusatzString
)){
498 authorString
= authorString
.replace(", "+nomZusatzString
, "");
500 if(CdmUtils
.isNotBlank(taxZusatzString
)){
501 authorString
= authorString
.replace(", "+taxZusatzString
, "");
503 if(authorString
.equals(RedListUtil
.AUCT
)){
506 if(!STRICT_TITLE_CHECK
&& authorString
.matches(".*ex.*ex.*")){
509 if(STRICT_TITLE_CHECK
){
510 if(!authorString
.equals(authorshipCache
)){
511 RedListUtil
.logMessage(id
, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil
.AUTOR
+": "+authorshipCache
+" <-> "+authorString
, logger
);
515 if(CdmUtils
.isNotBlank(authorString
) && !authorString
.startsWith(authorshipCache
)){
516 RedListUtil
.logMessage(id
, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil
.AUTOR
+": "+authorshipCache
+" <-> "+authorString
, logger
);
521 private void checkTaxonConsistency(long id
, String taxNameString
, String hybString
, String epi1String
, String epi2String
, String epi3String
, TaxonBase
<?
> taxonBase
, RedListGefaesspflanzenImportState state
) {
522 if(taxNameString
.split(RedListUtil
.HYB_SIGN
).length
>2){
523 RedListUtil
.logInfoMessage(id
, "multiple hybrid signs. No name check for "+taxNameString
, logger
);
527 String nameCache
= taxonBase
.getName().getNameCache().trim();
528 taxNameString
= taxNameString
.trim();
529 taxNameString
= taxNameString
.replaceAll(" +", " ");
532 if((hybString
.equals(RedListUtil
.HYB_X
) || hybString
.equals(RedListUtil
.HYB_N
))
533 && nameCache
.matches(".*\\s"+RedListUtil
.HYB_SIGN
+"\\w.*")){
534 taxNameString
= taxNameString
.replace(" "+RedListUtil
.HYB_SIGN
+" ", " "+RedListUtil
.HYB_SIGN
);//hybrid sign has no space after it in titleCache for binomial hybrids
535 taxNameString
= taxNameString
.replace(" x ", " "+RedListUtil
.HYB_SIGN
);//in some cases a standard 'x' is used
537 else if(hybString
.equals(RedListUtil
.HYB_G
)){
538 taxNameString
= taxNameString
.replace("X ", RedListUtil
.HYB_SIGN
);
540 else if(hybString
.equals(RedListUtil
.HYB_GF
)){
541 taxNameString
= taxNameString
.replace(" "+RedListUtil
.HYB_SIGN
+" ", " "+RedListUtil
.HYB_SIGN
);
543 else if(hybString
.equals(RedListUtil
.HYB_XF
)){
544 nameCache
= taxonBase
.getName().getTitleCache();
545 if(nameCache
.contains("sec")){
546 nameCache
= nameCache
.substring(0, nameCache
.indexOf("sec"));
548 if(!STRICT_TITLE_CHECK
){
549 taxNameString
= buildHybridFormula(epi1String
, epi2String
, epi3String
, taxonBase
.getName().getRank());
551 if(taxNameString
.split(RedListUtil
.HYB_SIGN
).length
==1){
552 taxNameString
= taxNameString
.replace(RedListUtil
.HYB_SIGN
+" ", RedListUtil
.HYB_SIGN
);
556 if(taxNameString
.endsWith("- Gruppe")){
557 taxNameString
= taxNameString
.replaceAll("- Gruppe", "species group");
559 if(taxNameString
.endsWith("- group")){
560 taxNameString
= taxNameString
.replaceAll("- group", "species group");
563 taxNameString
= taxNameString
.replace("agg.", "aggr.");
564 taxNameString
= taxNameString
.replace("[ranglos]", "[unranked]");
566 if(taxonBase
.getName().getRank()!=null){
567 if(taxonBase
.getName().getRank().equals(Rank
.PROLES())){
568 taxNameString
= taxNameString
.replace("proles", "prol.");
570 else if(taxonBase
.getName().getRank().equals(state
.getRank(RedListUtil
.uuidRankCollectionSpecies
))){
571 taxNameString
= taxNameString
.replace("\"Sammelart\"", "\"Coll. Species\"");
574 if(STRICT_TITLE_CHECK
){
575 if(!taxNameString
.trim().equals(nameCache
)){
576 RedListUtil
.logMessage(id
, "Taxon name inconsistent! taxon.nameCache <-> Column "+RedListUtil
.TAXNAME
+": "+nameCache
+" <-> "+taxNameString
, logger
);
580 if(!taxNameString
.startsWith(nameCache
)){
581 RedListUtil
.logMessage(id
, "Taxon name inconsistent! taxon.nameCache <-> Column "+RedListUtil
.TAXNAME
+": "+nameCache
+" <-> "+taxNameString
, logger
);
586 private Rank
makeRank(long id
, RedListGefaesspflanzenImportState state
, String rankStr
, boolean hasSpecificEpithet
) {
589 if(rankStr
.equals("ORA")){
590 //special handling for ORA because of two possibilities
591 if(hasSpecificEpithet
){
592 //re-load term because the representation was changed before
593 return (Rank
) getTermService().load(Rank
.uuidInfraspecificTaxon
);
596 return Rank
.UNRANKED_INFRAGENERIC();
599 else if(rankStr
.equals("SAM")){
600 return getRank(state
, RedListUtil
.uuidRankCollectionSpecies
, "Collective Species", "Collective Species", "\"Coll. Species\"", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.SpeciesGroup
);
602 else if(rankStr
.equals("MOD")){
603 return getRank(state
, RedListUtil
.uuidRankModification
, "Modification", "Modification", "modificatio", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
605 else if(rankStr
.equals("SPI")){
606 return getRank(state
, RedListUtil
.uuidRankSubspeciesPrincipes
, "Subspecies principes", "Subspecies principes", "subsp. princ.", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
608 else if(rankStr
.equals("KMB")){
609 return getRank(state
, RedListUtil
.uuidRankCombination
, "Combination", "Combination", "", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
611 else if(rankStr
.equals("'FO")){
612 return getRank(state
, RedListUtil
.uuidRankForme
, "Forme'", "Forme'", "", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
615 rank
= state
.getTransformer().getRankByKey(rankStr
);
617 } catch (UndefinedTransformerMethodException e
) {
621 RedListUtil
.logMessage(id
, rankStr
+" could not be associated to a known rank.", logger
);
626 private NomenclaturalStatusType
makeNomenclaturalStatus(long id
, RedListGefaesspflanzenImportState state
, String nomZusatzString
) {
627 NomenclaturalStatusType status
= null;
629 status
= state
.getTransformer().getNomenclaturalStatusByKey(nomZusatzString
);
630 } catch (UndefinedTransformerMethodException e
) {
634 RedListUtil
.logMessage(id
, nomZusatzString
+" could not be associated to a known nomenclatural status.", logger
);
642 public Map
<Object
, Map
<String
, ?
extends CdmBase
>> getRelatedObjectsForPartition(ResultSet rs
,
643 RedListGefaesspflanzenImportState state
) {
644 Map
<Object
, Map
<String
, ?
extends CdmBase
>> result
= new HashMap
<>();
645 Map
<String
, AgentBase
<?
>> authorMap
= new HashMap
<String
, AgentBase
<?
>>();
649 String authorKombString
= rs
.getString(RedListUtil
.AUTOR_KOMB
);
651 if(authorKombString
.contains(RedListUtil
.EX
)){
652 String
[] kombSplit
= authorKombString
.split(RedListUtil
.EX
);
653 for (int i
= 0; i
< kombSplit
.length
; i
++) {
654 if(!authorMap
.containsKey(kombSplit
[i
])){
655 authorMap
.put(kombSplit
[i
], getAgentService().load(state
.getAuthorMap().get(kombSplit
[i
])));
659 else if(CdmUtils
.isNotBlank(authorKombString
) && !authorMap
.containsKey(authorKombString
)){
660 authorMap
.put(authorKombString
, getAgentService().load(state
.getAuthorMap().get(authorKombString
)));
663 String authorBasiString
= rs
.getString(RedListUtil
.AUTOR_BASI
);
665 if(authorBasiString
.contains(RedListUtil
.EX
)){
666 String
[] basiSplit
= authorBasiString
.split(RedListUtil
.EX
);
667 for (int i
= 0; i
< basiSplit
.length
; i
++) {
668 if(!authorMap
.containsKey(basiSplit
[i
])){
669 authorMap
.put(basiSplit
[i
], getAgentService().load(state
.getAuthorMap().get(basiSplit
[i
])));
673 else if(CdmUtils
.isNotBlank(authorBasiString
) && !authorMap
.containsKey(authorBasiString
)){
674 authorMap
.put(authorBasiString
, getAgentService().load(state
.getAuthorMap().get(authorBasiString
)));
677 } catch (SQLException e
) {
680 result
.put(RedListUtil
.AUTHOR_NAMESPACE
, authorMap
);
686 protected boolean doCheck(RedListGefaesspflanzenImportState state
) {
691 protected boolean isIgnore(RedListGefaesspflanzenImportState state
) {