adapt app-import to v5.45
[cdmlib-apps.git] / app-import / src / main / java / eu / etaxonomy / cdm / io / redlist / gefaesspflanzen / RedListGefaesspflanzenImportNames.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.io.redlist.gefaesspflanzen;
10
11 import java.sql.ResultSet;
12 import java.sql.SQLException;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19
20 import org.apache.logging.log4j.LogManager;
21 import org.apache.logging.log4j.Logger;
22 import org.springframework.stereotype.Component;
23
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;
55
56 /**
57 * @author pplitzner
58 * @since Mar 1, 2016
59 */
60 @Component
61 @SuppressWarnings("serial")
62 public class RedListGefaesspflanzenImportNames extends DbImportBase<RedListGefaesspflanzenImportState, RedListGefaesspflanzenImportConfigurator> {
63
64 private static final Logger logger = LogManager.getLogger();
65
66 private static final String tableName = "Rote Liste Gefäßpflanzen";
67
68 private static final String pluralString = "names";
69
70 private static final boolean STRICT_TITLE_CHECK = false;
71
72 private ExtensionType extensionTypeFlor;
73
74 private ExtensionType extensionTypeAtlasIdx;
75
76 private ExtensionType extensionTypeKart;
77
78 private ExtensionType extensionTypeRl2015;
79
80 private ExtensionType extensionTypeEhrd;
81
82 private ExtensionType extensionTypeWissk;
83
84 public RedListGefaesspflanzenImportNames() {
85 super(tableName, pluralString);
86 }
87
88 @Override
89 protected String getIdQuery(RedListGefaesspflanzenImportState state) {
90 return "SELECT SEQNUM "
91 + "FROM V_TAXATLAS_D20_EXPORT t "
92 + " ORDER BY SEQNUM";
93 }
94
95 @Override
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);
101 return result;
102 }
103
104 @Override
105 protected void doInvoke(RedListGefaesspflanzenImportState state) {
106 makeExtensionTypes();
107 super.doInvoke(state);
108 }
109
110
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);
124 }
125
126 @Override
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<>();
131 try {
132 while (rs.next()){
133 makeSingleNameAndTaxon(state, rs, namesToSave, taxaToSave);
134
135 }
136 } catch (SQLException e) {
137 e.printStackTrace();
138 }
139
140 getNameService().saveOrUpdate(TaxonName.castAndDeproxy(namesToSave));
141 getTaxonService().saveOrUpdate(taxaToSave);
142 return true;
143 }
144
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);
156
157 //---NAME---
158 INonViralName name = importName(state, rs, namesToSave);
159
160
161 //--- AUTHORS ---
162 importAuthors(state, rs, name);
163
164 //---TAXON---
165 TaxonBase<?> taxonBase = importTaxon(rs, name, state);
166 if(taxonBase==null){
167 RedListUtil.logMessage(id, "!SERIOUS ERROR! Taxon for name "+name+" could not be created!", logger);
168 return;
169 }
170
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);
181
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);
185 }
186
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;
190
191 if(gesamtListeTaxon.isInstanceOf(Taxon.class)){
192 clonedTaxon = HibernateProxyHelper.deproxy(gesamtListeTaxon.clone(), Taxon.class);
193 }
194 else if(gesamtListeTaxon.isInstanceOf(Synonym.class)){
195 clonedTaxon = Taxon.NewInstance(gesamtListeTaxon.getName(), gesamtListeTaxon.getSec());
196 }
197 else{
198 RedListUtil.logMessage(id, "Taxon base "+gesamtListeTaxon+" is neither taxon nor synonym! Taxon could not be cloned", logger);
199 return;
200 }
201 ImportHelper.setOriginalSource(clonedTaxon, state.getTransactionalSourceReference(), id, sourceNameSpace);
202 taxaToSave.add(clonedTaxon);
203 }
204 }
205
206 private TaxonBase<?> importTaxon(ResultSet rs, INonViralName name, RedListGefaesspflanzenImportState state) throws SQLException {
207
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);
223
224 TaxonBase<?> taxonBase = null;
225 if(authorBasiString.trim().contains(RedListUtil.AUCT)){
226 taxonBase = Taxon.NewInstance(name, null);
227 taxonBase.setAppendedPhrase(RedListUtil.AUCT);
228 }
229 else if(gueltString.equals(RedListUtil.GUELT_ACCEPTED_TAXON)){
230 taxonBase = Taxon.NewInstance(name, null);
231 }
232 else if(gueltString.equals(RedListUtil.GUELT_SYNONYM) || gueltString.equals(RedListUtil.GUELT_BASIONYM)){
233 taxonBase = Synonym.NewInstance(name, null);
234 }
235 else{
236 RedListUtil.logMessage(id, "Taxon was not created!! Unknown value for "+RedListUtil.GUELT+"!", logger);
237 return null;
238 }
239
240 //common name
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()));
245 }
246
247 //add annotations
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);
254
255 //check taxon name consistency
256 checkTaxonConsistency(id, taxNameString, hybString, epi1String, epi2String, epi3String, taxonBase, state);
257 return taxonBase;
258 }
259
260 private void importAuthors(RedListGefaesspflanzenImportState state, ResultSet rs, INonViralName name) throws SQLException {
261
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);
269
270 //combination author
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);
282 }
283 else if(authorKombString.trim().contains(RedListUtil.AUCT)){
284 RedListUtil.logMessage(id, "AUCT information in "+RedListUtil.AUTOR_KOMB+" column", logger);
285 }
286 else if(CdmUtils.isNotBlank(authorKombString)){
287 TeamOrPersonBase<?> authorKomb = (TeamOrPersonBase<?>) state.getRelatedObject(RedListUtil.AUTHOR_NAMESPACE, authorKombString);
288 name.setCombinationAuthorship(authorKomb);
289 }
290 //basionym author
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);
295 }
296 else{
297 name.setExBasionymAuthorship(authorExBasi);
298 }
299 TeamOrPersonBase<?> authorBasi= (TeamOrPersonBase<?>) state.getRelatedObject(RedListUtil.AUTHOR_NAMESPACE, RedListUtil.getAuthorOfExAuthorshipString(authorBasiString));
300 if(CdmUtils.isBlank(authorKombString)){
301 name.setCombinationAuthorship(authorBasi);
302 }
303 else{
304 name.setBasionymAuthorship(authorBasi);
305 }
306 }
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);
312 }
313 else{
314 name.setBasionymAuthorship(authorBasi);
315 }
316 }
317
318 //check authorship consistency
319 String authorString = rs.getString(RedListUtil.AUTOR);
320 checkNameConsistency(id, nomZusatzString, taxZusatzString, zusatzString, authorString, hybString, name);
321 }
322
323 private INonViralName importName(RedListGefaesspflanzenImportState state, ResultSet rs, Set<ITaxonNameBase> namesToSave) throws SQLException {
324
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);
334
335 if(CdmUtils.isBlank(taxNameString) && CdmUtils.isBlank(ep1String)){
336 RedListUtil.logMessage(id, "No name found!", logger);
337 }
338
339 INonViralName name = null;
340 Rank rank = makeRank(id, state, rangString, CdmUtils.isNotBlank(ep3String));
341 //cultivar
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);
347 name = cultivar;
348 }
349 //botanical names
350 else{
351 name = TaxonNameFactory.NewBotanicalInstance(rank);
352
353 //ep1 should always be present
354 if(CdmUtils.isBlank(ep1String)){
355 RedListUtil.logMessage(id, RedListUtil.EPI1+" is empty!", logger);
356 }
357 name.setGenusOrUninomial(ep1String);
358 if(CdmUtils.isNotBlank(ep2String)){
359 if(rank!=null && rank.isInfraGenericButNotSpeciesGroup()){
360 name.setInfraGenericEpithet(ep2String);
361 }
362 else{
363 name.setSpecificEpithet(ep2String);
364 }
365 }
366 if(CdmUtils.isNotBlank(ep3String)){
367 name.setInfraSpecificEpithet(ep3String);
368 }
369
370
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);
381 if (matcher.find()){
382 status.setRuleConsidered(matcher.group(1));
383 }
384 }
385 name.addStatus(status);
386 }
387 }
388 //hybrid
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);
395 }
396 else if(hybString.equals(RedListUtil.HYB_X)){
397 name.setBinomHybrid(true);
398 }
399 else if(hybString.equals(RedListUtil.HYB_G)){
400 name.setMonomHybrid(true);
401 }
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);
406 }
407 else if(hybString.equals(RedListUtil.HYB_N)){
408 name = NonViralNameParserImpl.NewInstance().parseFullName(taxNameString, NomenclaturalCode.ICNAFP, rank);
409 }
410 else if(hybString.equals(RedListUtil.HYB_GF)){
411 if(ep1String.contains(RedListUtil.HYB_SIGN)){
412 name = NonViralNameParserImpl.NewInstance().parseFullName(ep1String, NomenclaturalCode.ICNAFP, rank);
413 }
414 else{
415 RedListUtil.logMessage(id, "HYB is "+hybString+" but "+RedListUtil.HYB+" does not contain "+RedListUtil.HYB_SIGN, logger);
416 }
417 }
418 else if(hybString.equals(RedListUtil.HYB_XS)){
419 //nothing to do
420 }
421 else{
422 logger.error("HYB value "+hybString+" not yet handled");
423 }
424 //save hybrid formula
425 if(CdmUtils.isNotBlank(formelString)){
426 Annotation annotation = Annotation.NewDefaultLanguageInstance(formelString);
427 annotation.setAnnotationType(AnnotationType.INTERNAL());
428 name.addAnnotation(annotation);
429 }
430 }
431 }
432
433 //add source
434 ImportHelper.setOriginalSource(name, state.getTransactionalSourceReference(), id, RedListUtil.NAME_NAMESPACE);
435
436 namesToSave.add(name);
437 return name;
438 }
439
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;
444 }
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);
454 }
455 else if(secondHybrid.length>1 && secondHybrid[0].matches("[A-Z].*")){
456 hybridFormula2 = split[1].trim();
457 }
458 if(CdmUtils.isNotBlank(ep3String)){
459 hybridFormula1 += " "+rank.getAbbreviation()+" "+ep3String;
460 hybridFormula2 += " "+rank.getAbbreviation()+" "+ep3String;
461 }
462 fullFormula = hybridFormula1+" "+RedListUtil.HYB_SIGN+" "+hybridFormula2;
463 }
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);
473 }
474 else if(secondHybrid.length>1 && secondHybrid[0].matches("[A-Z].*")){
475 hybridFormula2 = split[1].trim();
476 }
477 fullFormula = hybridFormula1+" "+RedListUtil.HYB_SIGN+" "+hybridFormula2;
478 }
479 return fullFormula;
480 }
481
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);
489 return;
490 }
491 return;
492 }
493
494 if(CdmUtils.isNotBlank(zusatzString)){
495 authorString = authorString.replace(", "+zusatzString, "");
496 }
497 if(CdmUtils.isNotBlank(nomZusatzString)){
498 authorString = authorString.replace(", "+nomZusatzString, "");
499 }
500 if(CdmUtils.isNotBlank(taxZusatzString)){
501 authorString = authorString.replace(", "+taxZusatzString, "");
502 }
503 if(authorString.equals(RedListUtil.AUCT)){
504 authorString = "";
505 }
506 if(!STRICT_TITLE_CHECK && authorString.matches(".*ex.*ex.*")){
507 return;
508 }
509 if(STRICT_TITLE_CHECK){
510 if(!authorString.equals(authorshipCache)){
511 RedListUtil.logMessage(id, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil.AUTOR+": "+authorshipCache+" <-> "+authorString, logger);
512 }
513 }
514 else{
515 if(CdmUtils.isNotBlank(authorString) && !authorString.startsWith(authorshipCache)){
516 RedListUtil.logMessage(id, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil.AUTOR+": "+authorshipCache+" <-> "+authorString, logger);
517 }
518 }
519 }
520
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);
524 return;
525 }
526
527 String nameCache = taxonBase.getName().getNameCache().trim();
528 taxNameString = taxNameString.trim();
529 taxNameString = taxNameString.replaceAll(" +", " ");
530
531
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
536 }
537 else if(hybString.equals(RedListUtil.HYB_G)){
538 taxNameString = taxNameString.replace("X ", RedListUtil.HYB_SIGN);
539 }
540 else if(hybString.equals(RedListUtil.HYB_GF)){
541 taxNameString = taxNameString.replace(" "+RedListUtil.HYB_SIGN+" ", " "+RedListUtil.HYB_SIGN);
542 }
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"));
547 }
548 if(!STRICT_TITLE_CHECK){
549 taxNameString = buildHybridFormula(epi1String, epi2String, epi3String, taxonBase.getName().getRank());
550 }
551 if(taxNameString.split(RedListUtil.HYB_SIGN).length==1){
552 taxNameString = taxNameString.replace(RedListUtil.HYB_SIGN+" ", RedListUtil.HYB_SIGN);
553 }
554 }
555
556 if(taxNameString.endsWith("- Gruppe")){
557 taxNameString = taxNameString.replaceAll("- Gruppe", "species group");
558 }
559 if(taxNameString.endsWith("- group")){
560 taxNameString = taxNameString.replaceAll("- group", "species group");
561 }
562
563 taxNameString = taxNameString.replace("agg.", "aggr.");
564 taxNameString = taxNameString.replace("[ranglos]", "[unranked]");
565
566 if(taxonBase.getName().getRank()!=null){
567 if(taxonBase.getName().getRank().equals(Rank.PROLES())){
568 taxNameString = taxNameString.replace("proles", "prol.");
569 }
570 else if(taxonBase.getName().getRank().equals(state.getRank(RedListUtil.uuidRankCollectionSpecies))){
571 taxNameString = taxNameString.replace("\"Sammelart\"", "\"Coll. Species\"");
572 }
573 }
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);
577 }
578 }
579 else{
580 if(!taxNameString.startsWith(nameCache)){
581 RedListUtil.logMessage(id, "Taxon name inconsistent! taxon.nameCache <-> Column "+RedListUtil.TAXNAME+": "+nameCache+" <-> "+taxNameString, logger);
582 }
583 }
584 }
585
586 private Rank makeRank(long id, RedListGefaesspflanzenImportState state, String rankStr, boolean hasSpecificEpithet) {
587 Rank rank = null;
588 try {
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);
594 }
595 else{
596 return Rank.UNRANKED_INFRAGENERIC();
597 }
598 }
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);
601 }
602 else if(rankStr.equals("MOD")){
603 return getRank(state, RedListUtil.uuidRankModification, "Modification", "Modification", "modificatio", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
604 }
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);
607 }
608 else if(rankStr.equals("KMB")){
609 return getRank(state, RedListUtil.uuidRankCombination, "Combination", "Combination", "", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
610 }
611 else if(rankStr.equals("'FO")){
612 return getRank(state, RedListUtil.uuidRankForme, "Forme'", "Forme'", "", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
613 }
614 else{
615 rank = state.getTransformer().getRankByKey(rankStr);
616 }
617 } catch (UndefinedTransformerMethodException e) {
618 e.printStackTrace();
619 }
620 if(rank==null){
621 RedListUtil.logMessage(id, rankStr+" could not be associated to a known rank.", logger);
622 }
623 return rank;
624 }
625
626 private NomenclaturalStatusType makeNomenclaturalStatus(long id, RedListGefaesspflanzenImportState state, String nomZusatzString) {
627 NomenclaturalStatusType status = null;
628 try {
629 status = state.getTransformer().getNomenclaturalStatusByKey(nomZusatzString);
630 } catch (UndefinedTransformerMethodException e) {
631 e.printStackTrace();
632 }
633 if(status==null){
634 RedListUtil.logMessage(id, nomZusatzString+" could not be associated to a known nomenclatural status.", logger);
635 }
636 return status;
637 }
638
639
640
641 @Override
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<?>>();
646
647 try {
648 while (rs.next()){
649 String authorKombString = rs.getString(RedListUtil.AUTOR_KOMB);
650
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])));
656 }
657 }
658 }
659 else if(CdmUtils.isNotBlank(authorKombString) && !authorMap.containsKey(authorKombString)){
660 authorMap.put(authorKombString, getAgentService().load(state.getAuthorMap().get(authorKombString)));
661 }
662
663 String authorBasiString = rs.getString(RedListUtil.AUTOR_BASI);
664 //basionym author
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])));
670 }
671 }
672 }
673 else if(CdmUtils.isNotBlank(authorBasiString) && !authorMap.containsKey(authorBasiString)){
674 authorMap.put(authorBasiString, getAgentService().load(state.getAuthorMap().get(authorBasiString)));
675 }
676 }
677 } catch (SQLException e) {
678 e.printStackTrace();
679 }
680 result.put(RedListUtil.AUTHOR_NAMESPACE, authorMap);
681
682 return result;
683 }
684
685 @Override
686 protected boolean doCheck(RedListGefaesspflanzenImportState state) {
687 return false;
688 }
689
690 @Override
691 protected boolean isIgnore(RedListGefaesspflanzenImportState state) {
692 return false;
693 }
694
695 }