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
.redlist
.gefaesspflanzen
;
12 import java
.sql
.ResultSet
;
13 import java
.sql
.SQLException
;
14 import java
.util
.HashMap
;
15 import java
.util
.HashSet
;
18 import java
.util
.regex
.Matcher
;
19 import java
.util
.regex
.Pattern
;
21 import org
.apache
.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
.AnnotatableEntity
;
34 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
35 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
36 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
37 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
38 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
39 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
40 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
41 import eu
.etaxonomy
.cdm
.model
.name
.BotanicalName
;
42 import eu
.etaxonomy
.cdm
.model
.name
.CultivarPlantName
;
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
.NonViralName
;
47 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
48 import eu
.etaxonomy
.cdm
.model
.name
.RankClass
;
49 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
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
.taxon
.TaxonRelationship
;
54 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
55 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
65 @SuppressWarnings("serial")
66 public class RedListGefaesspflanzenImportNames
extends DbImportBase
<RedListGefaesspflanzenImportState
, RedListGefaesspflanzenImportConfigurator
> {
68 private static final Logger logger
= Logger
.getLogger(RedListGefaesspflanzenImportNames
.class);
70 private static final String tableName
= "Rote Liste Gefäßpflanzen";
72 private static final String pluralString
= "names";
74 private static final boolean STRICT_TITLE_CHECK
= false;
76 public RedListGefaesspflanzenImportNames() {
77 super(tableName
, pluralString
);
81 protected String
getIdQuery(RedListGefaesspflanzenImportState state
) {
82 return "SELECT SEQNUM "
83 + "FROM V_TAXATLAS_D20_EXPORT t "
88 protected String
getRecordQuery(RedListGefaesspflanzenImportConfigurator config
) {
89 String result
= " SELECT * "
90 + " FROM V_TAXATLAS_D20_EXPORT t "
91 + " WHERE t.SEQNUM IN (@IDSET)";
92 result
= result
.replace("@IDSET", IPartitionedIO
.ID_LIST_TOKEN
);
97 protected void doInvoke(RedListGefaesspflanzenImportState state
) {
98 super.doInvoke(state
);
103 public boolean doPartition(ResultSetPartitioner partitioner
, RedListGefaesspflanzenImportState state
) {
104 ResultSet rs
= partitioner
.getResultSet();
105 Set
<TaxonNameBase
> namesToSave
= new HashSet
<TaxonNameBase
>();
106 Set
<TaxonBase
> taxaToSave
= new HashSet
<TaxonBase
>();
109 makeSingleNameAndTaxon(state
, rs
, namesToSave
, taxaToSave
);
112 } catch (SQLException e
) {
116 getNameService().saveOrUpdate(namesToSave
);
117 getTaxonService().saveOrUpdate(taxaToSave
);
121 private void makeSingleNameAndTaxon(RedListGefaesspflanzenImportState state
, ResultSet rs
, Set
<TaxonNameBase
> namesToSave
, Set
<TaxonBase
> taxaToSave
)
122 throws SQLException
{
123 long id
= rs
.getLong(RedListUtil
.NAMNR
);
124 String clTaxonString
= rs
.getString(RedListUtil
.CL_TAXON
);
125 String relationE
= rs
.getString(RedListUtil
.E
);
126 String relationW
= rs
.getString(RedListUtil
.W
);
127 String relationK
= rs
.getString(RedListUtil
.K
);
128 String relationAW
= rs
.getString(RedListUtil
.AW
);
129 String relationAO
= rs
.getString(RedListUtil
.AO
);
130 String relationR
= rs
.getString(RedListUtil
.R
);
131 String relationO
= rs
.getString(RedListUtil
.O
);
132 String relationS
= rs
.getString(RedListUtil
.S
);
135 NonViralName
<?
> name
= importName(state
, rs
, namesToSave
);
139 importAuthors(state
, rs
, name
);
142 TaxonBase
<?
> taxonBase
= importTaxon(rs
, name
, state
);
144 RedListUtil
.logMessage(id
, "Taxon for name "+name
+" could not be created.", logger
);
148 //---CONCEPT RELATIONSHIPS---
149 //E, W, K, AW, AO, R, O, S
150 cloneTaxon(taxonBase
, relationE
, RedListUtil
.CLASSIFICATION_NAMESPACE_E
, taxaToSave
, id
, state
);
151 cloneTaxon(taxonBase
, relationW
, RedListUtil
.CLASSIFICATION_NAMESPACE_W
, taxaToSave
, id
, state
);
152 cloneTaxon(taxonBase
, relationK
, RedListUtil
.CLASSIFICATION_NAMESPACE_K
, taxaToSave
, id
, state
);
153 cloneTaxon(taxonBase
, relationAW
, RedListUtil
.CLASSIFICATION_NAMESPACE_AW
, taxaToSave
, id
, state
);
154 cloneTaxon(taxonBase
, relationAO
, RedListUtil
.CLASSIFICATION_NAMESPACE_AO
, taxaToSave
, id
, state
);
155 cloneTaxon(taxonBase
, relationR
, RedListUtil
.CLASSIFICATION_NAMESPACE_R
, taxaToSave
, id
, state
);
156 cloneTaxon(taxonBase
, relationO
, RedListUtil
.CLASSIFICATION_NAMESPACE_O
, taxaToSave
, id
, state
);
157 cloneTaxon(taxonBase
, relationS
, RedListUtil
.CLASSIFICATION_NAMESPACE_S
, taxaToSave
, id
, state
);
159 TaxonBase
<?
> checklistTaxon
= null;
160 if(CdmUtils
.isNotBlank(clTaxonString
) && !clTaxonString
.trim().equals("-")){
161 checklistTaxon
= (TaxonBase
<?
>) taxonBase
.clone();
162 if(checklistTaxon
.isInstanceOf(Taxon
.class)){
163 TaxonRelationship relation
= HibernateProxyHelper
.deproxy(checklistTaxon
, Taxon
.class).addTaxonRelation(HibernateProxyHelper
.deproxy(taxonBase
, Taxon
.class), TaxonRelationshipType
.CONGRUENT_TO(), null, null);
164 relation
.setDoubtful(true);
167 ImportHelper
.setOriginalSource(checklistTaxon
, state
.getTransactionalSourceReference(), id
, RedListUtil
.TAXON_CHECKLISTE_NAMESPACE
);
168 taxaToSave
.add(checklistTaxon
);
171 //NOTE: the source has to be added after cloning or otherwise the clone would also get the source
172 ImportHelper
.setOriginalSource(taxonBase
, state
.getTransactionalSourceReference(), id
, RedListUtil
.TAXON_GESAMTLISTE_NAMESPACE
);
173 taxaToSave
.add(taxonBase
);
176 private void cloneTaxon(final TaxonBase
<?
> gesamtListeTaxon
, String relationString
, String sourceNameSpace
, Set
<TaxonBase
> taxaToSave
, long id
, RedListGefaesspflanzenImportState state
){
177 if(CdmUtils
.isNotBlank(relationString
) && !relationString
.equals(".")){
178 Taxon clonedTaxon
= null;
180 if(gesamtListeTaxon
.isInstanceOf(Taxon
.class)){
181 clonedTaxon
= HibernateProxyHelper
.deproxy(gesamtListeTaxon
.clone(), Taxon
.class);
183 else if(gesamtListeTaxon
.isInstanceOf(Synonym
.class)){
184 clonedTaxon
= Taxon
.NewInstance(gesamtListeTaxon
.getName(), gesamtListeTaxon
.getSec());
187 RedListUtil
.logMessage(id
, "Taxon base "+gesamtListeTaxon
+" is neither taxon nor synonym! Taxon could not be cloned", logger
);
190 ImportHelper
.setOriginalSource(clonedTaxon
, state
.getTransactionalSourceReference(), id
, sourceNameSpace
);
191 taxaToSave
.add(clonedTaxon
);
195 private TaxonBase
<?
> importTaxon(ResultSet rs
, NonViralName
<?
> name
, RedListGefaesspflanzenImportState state
) throws SQLException
{
197 long id
= rs
.getLong(RedListUtil
.NAMNR
);
198 String taxNameString
= rs
.getString(RedListUtil
.TAXNAME
);
199 String epi1String
= rs
.getString(RedListUtil
.EPI1
);
200 String epi2String
= rs
.getString(RedListUtil
.EPI2
);
201 String epi3String
= rs
.getString(RedListUtil
.EPI3
);
202 String gueltString
= rs
.getString(RedListUtil
.GUELT
);
203 String trivialString
= rs
.getString(RedListUtil
.TRIVIAL
);
204 String authorBasiString
= rs
.getString(RedListUtil
.AUTOR_BASI
);
205 String hybString
= rs
.getString(RedListUtil
.HYB
);
206 String florString
= rs
.getString(RedListUtil
.FLOR
);
207 String atlasIdxString
= rs
.getString(RedListUtil
.ATLAS_IDX
);
208 String kartString
= rs
.getString(RedListUtil
.KART
);
209 String rl2015String
= rs
.getString(RedListUtil
.RL2015
);
210 String ehrdString
= rs
.getString(RedListUtil
.EHRD
);
211 String wisskString
= rs
.getString(RedListUtil
.WISSK
);
213 TaxonBase
<?
> taxonBase
= null;
214 if(authorBasiString
.trim().contains(RedListUtil
.AUCT
)){
215 taxonBase
= Taxon
.NewInstance(name
, null);
216 taxonBase
.setAppendedPhrase(RedListUtil
.AUCT
);
218 else if(gueltString
.equals(RedListUtil
.GUELT_ACCEPTED_TAXON
)){
219 taxonBase
= Taxon
.NewInstance(name
, null);
221 else if(gueltString
.equals(RedListUtil
.GUELT_SYNONYM
) || gueltString
.equals(RedListUtil
.GUELT_BASIONYM
)){
222 taxonBase
= Synonym
.NewInstance(name
, null);
229 if(taxonBase
.isInstanceOf(Taxon
.class) && trivialString
!=null){
230 Taxon taxon
= HibernateProxyHelper
.deproxy(taxonBase
, Taxon
.class);
231 TaxonDescription description
= TaxonDescription
.NewInstance(taxon
);
232 description
.addElement(CommonTaxonName
.NewInstance(trivialString
, Language
.GERMAN()));
236 addAnnotation(RedListUtil
.FLOR
+": "+florString
, taxonBase
);
237 addAnnotation(RedListUtil
.ATLAS_IDX
+": "+atlasIdxString
, taxonBase
);
238 addAnnotation(RedListUtil
.KART
+": "+kartString
, taxonBase
);
239 addAnnotation(RedListUtil
.RL2015
+": "+rl2015String
, taxonBase
);
240 addAnnotation(RedListUtil
.EHRD
+": "+ehrdString
, taxonBase
);
241 addAnnotation(RedListUtil
.WISSK
+": "+wisskString
, taxonBase
);
243 //check taxon name consistency
244 checkTaxonConsistency(id
, taxNameString
, hybString
, epi1String
, epi2String
, epi3String
, taxonBase
, state
);
248 private void addAnnotation(String string
, AnnotatableEntity entity
) {
249 if(CdmUtils
.isNotBlank(string
)){
250 entity
.addAnnotation(Annotation
.NewInstance(string
, AnnotationType
.TECHNICAL(), Language
.GERMAN()));
254 private void importAuthors(RedListGefaesspflanzenImportState state
, ResultSet rs
, NonViralName
<?
> name
) throws SQLException
{
256 long id
= rs
.getLong(RedListUtil
.NAMNR
);
257 String nomZusatzString
= rs
.getString(RedListUtil
.NOM_ZUSATZ
);
258 String taxZusatzString
= rs
.getString(RedListUtil
.TAX_ZUSATZ
);
259 String zusatzString
= rs
.getString(RedListUtil
.ZUSATZ
);
260 String authorKombString
= rs
.getString(RedListUtil
.AUTOR_KOMB
);
261 String authorBasiString
= rs
.getString(RedListUtil
.AUTOR_BASI
);
262 String hybString
= rs
.getString(RedListUtil
.HYB
);
265 if(authorKombString
.contains(RedListUtil
.EX
)){
266 // multiple ex authors will be reduced to only the last one
267 // e.g. Almq. ex Sternström ex Dahlst. -> Almq. ex Dahlst.
268 //first author is ex combination author
269 String exAuthorString
= RedListUtil
.getExAuthorOfExAuthorshipString(authorKombString
);
270 TeamOrPersonBase
<?
> exAuthor
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, exAuthorString
);
271 name
.setExCombinationAuthorship(exAuthor
);
272 //the last author is the combination author
273 String authorString
= RedListUtil
.getAuthorOfExAuthorshipString(authorKombString
);
274 TeamOrPersonBase
<?
> combAuthor
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, authorString
);
275 name
.setCombinationAuthorship(combAuthor
);
277 else if(authorKombString
.trim().contains(RedListUtil
.AUCT
)){
278 RedListUtil
.logMessage(id
, "AUCT information in "+RedListUtil
.AUTOR_KOMB
+" column", logger
);
280 else if(CdmUtils
.isNotBlank(authorKombString
)){
281 TeamOrPersonBase
<?
> authorKomb
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, authorKombString
);
282 name
.setCombinationAuthorship(authorKomb
);
285 if(authorBasiString
.contains(RedListUtil
.EX
)){
286 TeamOrPersonBase
<?
> authorExBasi
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, RedListUtil
.getExAuthorOfExAuthorshipString(authorBasiString
));
287 if(CdmUtils
.isBlank(authorKombString
)){
288 name
.setExCombinationAuthorship(authorExBasi
);
291 name
.setExBasionymAuthorship(authorExBasi
);
293 TeamOrPersonBase
<?
> authorBasi
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, RedListUtil
.getAuthorOfExAuthorshipString(authorBasiString
));
294 if(CdmUtils
.isBlank(authorKombString
)){
295 name
.setCombinationAuthorship(authorBasi
);
298 name
.setBasionymAuthorship(authorBasi
);
301 else if(CdmUtils
.isNotBlank(authorBasiString
)){
302 //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
303 TeamOrPersonBase
<?
> authorBasi
= (TeamOrPersonBase
<?
>) state
.getRelatedObject(RedListUtil
.AUTHOR_NAMESPACE
, authorBasiString
);
304 if(CdmUtils
.isBlank(authorKombString
)){
305 name
.setCombinationAuthorship(authorBasi
);
308 name
.setBasionymAuthorship(authorBasi
);
312 //check authorship consistency
313 String authorString
= rs
.getString(RedListUtil
.AUTOR
);
314 checkNameConsistency(id
, nomZusatzString
, taxZusatzString
, zusatzString
, authorString
, hybString
, name
);
317 private NonViralName
<?
> importName(RedListGefaesspflanzenImportState state
, ResultSet rs
, Set
<TaxonNameBase
> namesToSave
) throws SQLException
{
319 long id
= rs
.getLong(RedListUtil
.NAMNR
);
320 String taxNameString
= rs
.getString(RedListUtil
.TAXNAME
);
321 String rangString
= rs
.getString(RedListUtil
.RANG
);
322 String ep1String
= rs
.getString(RedListUtil
.EPI1
);
323 String ep2String
= rs
.getString(RedListUtil
.EPI2
);
324 String ep3String
= rs
.getString(RedListUtil
.EPI3
);
325 String nomZusatzString
= rs
.getString(RedListUtil
.NOM_ZUSATZ
);
326 String hybString
= rs
.getString(RedListUtil
.HYB
);
327 String formelString
= rs
.getString(RedListUtil
.FORMEL
);
329 if(CdmUtils
.isBlank(taxNameString
) && CdmUtils
.isBlank(ep1String
)){
330 RedListUtil
.logMessage(id
, "No name found!", logger
);
333 NonViralName
<?
> name
= null;
334 Rank rank
= makeRank(id
, state
, rangString
, CdmUtils
.isNotBlank(ep3String
));
336 if(rank
!= null && rank
.equals(Rank
.CULTIVAR())){
337 CultivarPlantName cultivar
= CultivarPlantName
.NewInstance(rank
);
338 cultivar
.setGenusOrUninomial(ep1String
);
339 cultivar
.setSpecificEpithet(ep2String
);
340 cultivar
.setCultivarName(ep3String
);
345 name
= BotanicalName
.NewInstance(rank
);
347 //ep1 should always be present
348 if(CdmUtils
.isBlank(ep1String
)){
349 RedListUtil
.logMessage(id
, RedListUtil
.EPI1
+" is empty!", logger
);
351 name
.setGenusOrUninomial(ep1String
);
352 if(CdmUtils
.isNotBlank(ep2String
)){
353 if(rank
!=null && rank
.isInfraGenericButNotSpeciesGroup()){
354 name
.setInfraGenericEpithet(ep2String
);
357 name
.setSpecificEpithet(ep2String
);
360 if(CdmUtils
.isNotBlank(ep3String
)){
361 name
.setInfraSpecificEpithet(ep3String
);
365 //nomenclatural status
366 if(CdmUtils
.isNotBlank(nomZusatzString
)){
367 NomenclaturalStatusType statusType
= makeNomenclaturalStatus(id
, state
, nomZusatzString
);
368 if(statusType
!=null){
369 NomenclaturalStatus status
= NomenclaturalStatus
.NewInstance(statusType
);
370 //special case for invalid names where the DB entry contains
371 //additional information in brackets e.g. "nom. inval. (sine basion.)"
372 if(statusType
.equals(NomenclaturalStatusType
.INVALID()) || statusType
.equals(NomenclaturalStatusType
.REJECTED()) ){
373 Pattern pattern
= Pattern
.compile("\\((.*?)\\)");
374 Matcher matcher
= pattern
.matcher(nomZusatzString
);
376 status
.setRuleConsidered(matcher
.group(1));
379 name
.addStatus(status
);
383 if(CdmUtils
.isNotBlank(hybString
)){
384 //more than two hybrids not yet handled by name parser
385 //TODO: use parser when implemented to fully support hybrids
386 if(taxNameString
.split(RedListUtil
.HYB_SIGN
).length
>2){
387 name
= BotanicalName
.NewInstance(rank
);
388 name
.setTitleCache(taxNameString
, true);
390 else if(hybString
.equals(RedListUtil
.HYB_X
)){
391 name
.setBinomHybrid(true);
393 else if(hybString
.equals(RedListUtil
.HYB_G
)){
394 name
.setMonomHybrid(true);
396 else if(hybString
.equals(RedListUtil
.HYB_XF
) || hybString
.equals(RedListUtil
.HYB_XU
)){
397 name
.setHybridFormula(true);
398 String fullFormula
= buildHybridFormula(ep1String
, ep2String
, ep3String
, rank
);
399 name
= NonViralNameParserImpl
.NewInstance().parseFullName(fullFormula
, NomenclaturalCode
.ICNAFP
, rank
);
401 else if(hybString
.equals(RedListUtil
.HYB_N
)){
402 name
= NonViralNameParserImpl
.NewInstance().parseFullName(taxNameString
, NomenclaturalCode
.ICNAFP
, rank
);
404 else if(hybString
.equals(RedListUtil
.HYB_GF
)){
405 if(ep1String
.contains(RedListUtil
.HYB_SIGN
)){
406 name
= NonViralNameParserImpl
.NewInstance().parseFullName(ep1String
, NomenclaturalCode
.ICNAFP
, rank
);
409 RedListUtil
.logMessage(id
, "HYB is "+hybString
+" but "+RedListUtil
.HYB
+" does not contain "+RedListUtil
.HYB_SIGN
, logger
);
412 else if(hybString
.equals(RedListUtil
.HYB_XS
)){
416 logger
.error("HYB value "+hybString
+" not yet handled");
418 //save hybrid formula
419 if(CdmUtils
.isNotBlank(formelString
)){
420 Annotation annotation
= Annotation
.NewDefaultLanguageInstance(formelString
);
421 annotation
.setAnnotationType(AnnotationType
.TECHNICAL());
422 name
.addAnnotation(annotation
);
428 ImportHelper
.setOriginalSource(name
, state
.getTransactionalSourceReference(), id
, RedListUtil
.NAME_NAMESPACE
);
430 namesToSave
.add(name
);
434 private String
buildHybridFormula(String ep1String
, String ep2String
, String ep3String
, Rank rank
) {
435 String fullFormula
= null;
436 if(ep1String
.contains(RedListUtil
.HYB_SIGN
)){
437 fullFormula
= ep1String
;
439 else if(ep2String
.contains(RedListUtil
.HYB_SIGN
)){
440 String
[] split
= ep2String
.split(RedListUtil
.HYB_SIGN
);
441 String hybridFormula1
= ep1String
+" "+split
[0].trim();
442 String hybridFormula2
= ep1String
+" "+split
[1].trim();
443 //check if the genus is mentioned in EP2 or not
444 String
[] secondHybrid
= split
[1].trim().split(" ");
445 //check if the genus is abbreviated like e.g. Centaurea jacea × C. decipiens
446 if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z]\\.")){
447 hybridFormula2
= ep1String
+" "+split
[1].trim().substring(3);
449 else if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z].*")){
450 hybridFormula2
= split
[1].trim();
452 if(CdmUtils
.isNotBlank(ep3String
)){
453 hybridFormula1
+= " "+rank
.getAbbreviation()+" "+ep3String
;
454 hybridFormula2
+= " "+rank
.getAbbreviation()+" "+ep3String
;
456 fullFormula
= hybridFormula1
+" "+RedListUtil
.HYB_SIGN
+" "+hybridFormula2
;
458 else if(ep3String
.contains(RedListUtil
.HYB_SIGN
)){
459 String
[] split
= ep3String
.split(RedListUtil
.HYB_SIGN
);
460 String hybridFormula1
= ep1String
+" "+ep2String
+" "+rank
.getAbbreviation()+" "+split
[0].trim();
461 String hybridFormula2
= ep1String
+" "+ep2String
+" "+rank
.getAbbreviation()+" "+split
[1].trim();
462 //check if the genus is mentioned in EP3 or not
463 String
[] secondHybrid
= split
[1].trim().split(" ");
464 //check if the genus is abbreviated like e.g. Centaurea jacea jacea × C. jacea subsp. decipiens
465 if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z]\\.")){
466 hybridFormula2
= ep1String
+" "+split
[1].trim().substring(3);
468 else if(secondHybrid
.length
>1 && secondHybrid
[0].matches("[A-Z].*")){
469 hybridFormula2
= split
[1].trim();
471 fullFormula
= hybridFormula1
+" "+RedListUtil
.HYB_SIGN
+" "+hybridFormula2
;
476 private void checkNameConsistency(long id
, String nomZusatzString
, String taxZusatzString
,
477 String zusatzString
, String authorString
, String hybString
, NonViralName
<?
> name
) {
478 String authorshipCache
= name
.getAuthorshipCache();
479 //FIXME: remove split length check when name parser can parse multiple hybrid parents
480 if(hybString
.equals(RedListUtil
.HYB_XF
) && name
.getTitleCache().split(RedListUtil
.HYB_SIGN
).length
==2){
481 if(name
.getHybridChildRelations().isEmpty()){
482 RedListUtil
.logMessage(id
, "Hybrid formula but no hybrid child relations: "+name
.getTitleCache(), logger
);
488 if(CdmUtils
.isNotBlank(zusatzString
)){
489 authorString
= authorString
.replace(", "+zusatzString
, "");
491 if(CdmUtils
.isNotBlank(nomZusatzString
)){
492 authorString
= authorString
.replace(", "+nomZusatzString
, "");
494 if(CdmUtils
.isNotBlank(taxZusatzString
)){
495 authorString
= authorString
.replace(", "+taxZusatzString
, "");
497 if(authorString
.equals(RedListUtil
.AUCT
)){
500 if(authorString
.contains(RedListUtil
.EX
)){
501 String exAuthor
= RedListUtil
.getExAuthorOfExAuthorshipString(authorString
);
502 String author
= RedListUtil
.getAuthorOfExAuthorshipString(authorString
);
503 authorString
= exAuthor
+RedListUtil
.EX
+author
;
505 if(STRICT_TITLE_CHECK
){
506 if(!authorString
.equals(authorshipCache
)){
507 RedListUtil
.logMessage(id
, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil
.AUTOR
+": "+authorshipCache
+" <-> "+authorString
, logger
);
511 if(CdmUtils
.isNotBlank(authorString
) && !authorString
.startsWith(authorshipCache
)){
512 RedListUtil
.logMessage(id
, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil
.AUTOR
+": "+authorshipCache
+" <-> "+authorString
, logger
);
517 private void checkTaxonConsistency(long id
, String taxNameString
, String hybString
, String epi1String
, String epi2String
, String epi3String
, TaxonBase
<?
> taxonBase
, RedListGefaesspflanzenImportState state
) {
518 if(taxNameString
.split(RedListUtil
.HYB_SIGN
).length
>2){
519 RedListUtil
.logInfoMessage(id
, "multiple hybrid signs. No name check for "+taxNameString
, logger
);
523 String nameCache
= HibernateProxyHelper
.deproxy(taxonBase
.getName(), NonViralName
.class).getNameCache().trim();
524 taxNameString
= taxNameString
.trim();
525 taxNameString
= taxNameString
.replaceAll(" +", " ");
528 if(hybString
.equals(RedListUtil
.HYB_X
) || hybString
.equals(RedListUtil
.HYB_N
)){
529 taxNameString
= taxNameString
.replace(" "+RedListUtil
.HYB_SIGN
+" ", " "+RedListUtil
.HYB_SIGN
);//hybrid sign has no space after it in titleCache for binomial hybrids
530 taxNameString
= taxNameString
.replace(" x ", " "+RedListUtil
.HYB_SIGN
);//in some cases a standard 'x' is used
532 else if(hybString
.equals(RedListUtil
.HYB_G
)){
533 taxNameString
= taxNameString
.replace("X ", RedListUtil
.HYB_SIGN
);
535 else if(hybString
.equals(RedListUtil
.HYB_GF
)){
536 taxNameString
= taxNameString
.replace(" "+RedListUtil
.HYB_SIGN
+" ", " "+RedListUtil
.HYB_SIGN
);
538 else if(hybString
.equals(RedListUtil
.HYB_XF
)){
539 nameCache
= taxonBase
.getName().getTitleCache();
540 if(nameCache
.contains("sec")){
541 nameCache
= nameCache
.substring(0, nameCache
.indexOf("sec"));
543 if(!STRICT_TITLE_CHECK
){
544 taxNameString
= buildHybridFormula(epi1String
, epi2String
, epi3String
, taxonBase
.getName().getRank());
546 if(taxNameString
.split(RedListUtil
.HYB_SIGN
).length
==1){
547 taxNameString
= taxNameString
.replace(RedListUtil
.HYB_SIGN
+" ", RedListUtil
.HYB_SIGN
);
551 if(taxNameString
.endsWith("- Gruppe")){
552 taxNameString
= taxNameString
.replaceAll("- Gruppe", "species group");
554 if(taxNameString
.endsWith("- group")){
555 taxNameString
= taxNameString
.replaceAll("- group", "species group");
558 taxNameString
= taxNameString
.replace("agg.", "aggr.");
559 taxNameString
= taxNameString
.replace("[ranglos]", "[unranked]");
561 if(taxonBase
.getName().getRank()!=null){
562 if(taxonBase
.getName().getRank().equals(Rank
.PROLES())){
563 taxNameString
= taxNameString
.replace("proles", "prol.");
565 else if(taxonBase
.getName().getRank().equals(state
.getRank(RedListUtil
.uuidRankCollectionSpecies
))){
566 taxNameString
= taxNameString
.replace("\"Sammelart\"", "\"Coll. Species\"");
569 if(STRICT_TITLE_CHECK
){
570 if(!taxNameString
.trim().equals(nameCache
)){
571 RedListUtil
.logMessage(id
, "Taxon name inconsistent! taxon.nameCache <-> Column "+RedListUtil
.TAXNAME
+": "+nameCache
+" <-> "+taxNameString
, logger
);
575 if(!taxNameString
.startsWith(nameCache
)){
576 RedListUtil
.logMessage(id
, "Taxon name inconsistent! taxon.nameCache <-> Column "+RedListUtil
.TAXNAME
+": "+nameCache
+" <-> "+taxNameString
, logger
);
581 private Rank
makeRank(long id
, RedListGefaesspflanzenImportState state
, String rankStr
, boolean hasSpecificEpithet
) {
584 if(rankStr
.equals("ORA")){
585 //special handling for ORA because of two possibilities
586 if(hasSpecificEpithet
){
587 //re-load term because the representation was changed before
588 return (Rank
) getTermService().load(Rank
.uuidInfraspecificTaxon
);
591 return Rank
.UNRANKED_INFRAGENERIC();
594 else if(rankStr
.equals("SAM")){
595 return getRank(state
, RedListUtil
.uuidRankCollectionSpecies
, "Collective Species", "Collective Species", "\"Coll. Species\"", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.SpeciesGroup
);
597 else if(rankStr
.equals("SPR")){
598 return getRank(state
, RedListUtil
.uuidRankSubproles
, "Subproles", "Subproles", "subproles", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
600 else if(rankStr
.equals("MOD")){
601 return getRank(state
, RedListUtil
.uuidRankModification
, "Modification", "Modification", "modificatio", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
603 else if(rankStr
.equals("LUS")){
604 return getRank(state
, RedListUtil
.uuidRankLusus
, "Lusus", "Lusus", "lusus", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
606 else if(rankStr
.equals("SPI")){
607 return getRank(state
, RedListUtil
.uuidRankSubspeciesPrincipes
, "Subspecies principes", "Subspecies principes", "subsp. princ.", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
609 else if(rankStr
.equals("KMB")){
610 return getRank(state
, RedListUtil
.uuidRankCombination
, "Combination", "Combination", "", (OrderedTermVocabulary
<Rank
>) Rank
.GENUS().getVocabulary(), null, RankClass
.Infraspecific
);
613 rank
= state
.getTransformer().getRankByKey(rankStr
);
615 } catch (UndefinedTransformerMethodException e
) {
619 RedListUtil
.logMessage(id
, rankStr
+" could not be associated to a known rank.", logger
);
624 private NomenclaturalStatusType
makeNomenclaturalStatus(long id
, RedListGefaesspflanzenImportState state
, String nomZusatzString
) {
625 NomenclaturalStatusType status
= null;
627 status
= state
.getTransformer().getNomenclaturalStatusByKey(nomZusatzString
);
628 } catch (UndefinedTransformerMethodException e
) {
632 RedListUtil
.logMessage(id
, nomZusatzString
+" could not be associated to a known nomenclatural status.", logger
);
640 public Map
<Object
, Map
<String
, ?
extends CdmBase
>> getRelatedObjectsForPartition(ResultSet rs
,
641 RedListGefaesspflanzenImportState state
) {
642 Map
<Object
, Map
<String
, ?
extends CdmBase
>> result
= new HashMap
<>();
643 Map
<String
, AgentBase
<?
>> authorMap
= new HashMap
<String
, AgentBase
<?
>>();
647 String authorKombString
= rs
.getString(RedListUtil
.AUTOR_KOMB
);
649 if(authorKombString
.contains(RedListUtil
.EX
)){
650 String
[] kombSplit
= authorKombString
.split(RedListUtil
.EX
);
651 for (int i
= 0; i
< kombSplit
.length
; i
++) {
652 if(!authorMap
.containsKey(kombSplit
[i
])){
653 authorMap
.put(kombSplit
[i
], getAgentService().load(state
.getAuthorMap().get(kombSplit
[i
])));
657 else if(CdmUtils
.isNotBlank(authorKombString
) && !authorMap
.containsKey(authorKombString
)){
658 authorMap
.put(authorKombString
, getAgentService().load(state
.getAuthorMap().get(authorKombString
)));
661 String authorBasiString
= rs
.getString(RedListUtil
.AUTOR_BASI
);
663 if(authorBasiString
.contains(RedListUtil
.EX
)){
664 String
[] basiSplit
= authorBasiString
.split(RedListUtil
.EX
);
665 for (int i
= 0; i
< basiSplit
.length
; i
++) {
666 if(!authorMap
.containsKey(basiSplit
[i
])){
667 authorMap
.put(basiSplit
[i
], getAgentService().load(state
.getAuthorMap().get(basiSplit
[i
])));
671 else if(CdmUtils
.isNotBlank(authorBasiString
) && !authorMap
.containsKey(authorBasiString
)){
672 authorMap
.put(authorBasiString
, getAgentService().load(state
.getAuthorMap().get(authorBasiString
)));
675 } catch (SQLException e
) {
678 result
.put(RedListUtil
.AUTHOR_NAMESPACE
, authorMap
);
684 protected boolean doCheck(RedListGefaesspflanzenImportState state
) {
689 protected boolean isIgnore(RedListGefaesspflanzenImportState state
) {