#5448 Change abbrev label of unranked infraspecfic rank before importing
[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
10 package eu.etaxonomy.cdm.io.redlist.gefaesspflanzen;
11
12 import java.sql.ResultSet;
13 import java.sql.SQLException;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
20
21 import org.apache.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.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;
56
57 /**
58 *
59 * @author pplitzner
60 * @date Mar 1, 2016
61 *
62 */
63
64 @Component
65 @SuppressWarnings("serial")
66 public class RedListGefaesspflanzenImportNames extends DbImportBase<RedListGefaesspflanzenImportState, RedListGefaesspflanzenImportConfigurator> {
67
68 private static final Logger logger = Logger.getLogger(RedListGefaesspflanzenImportNames.class);
69
70 private static final String tableName = "Rote Liste Gefäßpflanzen";
71
72 private static final String pluralString = "names";
73
74 private static final boolean STRICT_TITLE_CHECK = false;
75
76 public RedListGefaesspflanzenImportNames() {
77 super(tableName, pluralString);
78 }
79
80 @Override
81 protected String getIdQuery(RedListGefaesspflanzenImportState state) {
82 return "SELECT SEQNUM "
83 + "FROM V_TAXATLAS_D20_EXPORT t "
84 + " ORDER BY SEQNUM";
85 }
86
87 @Override
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);
93 return result;
94 }
95
96 @Override
97 protected void doInvoke(RedListGefaesspflanzenImportState state) {
98 super.doInvoke(state);
99 }
100
101
102 @Override
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>();
107 try {
108 while (rs.next()){
109 makeSingleNameAndTaxon(state, rs, namesToSave, taxaToSave);
110
111 }
112 } catch (SQLException e) {
113 e.printStackTrace();
114 }
115
116 getNameService().saveOrUpdate(namesToSave);
117 getTaxonService().saveOrUpdate(taxaToSave);
118 return true;
119 }
120
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);
133
134 //---NAME---
135 NonViralName<?> name = importName(state, rs, namesToSave);
136
137
138 //--- AUTHORS ---
139 importAuthors(state, rs, name);
140
141 //---TAXON---
142 TaxonBase<?> taxonBase = importTaxon(rs, name, state);
143 if(taxonBase==null){
144 RedListUtil.logMessage(id, "Taxon for name "+name+" could not be created.", logger);
145 return;
146 }
147
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);
158 //checklist
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);
165 }
166
167 ImportHelper.setOriginalSource(checklistTaxon, state.getTransactionalSourceReference(), id, RedListUtil.TAXON_CHECKLISTE_NAMESPACE);
168 taxaToSave.add(checklistTaxon);
169 }
170
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);
174 }
175
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;
179
180 if(gesamtListeTaxon.isInstanceOf(Taxon.class)){
181 clonedTaxon = HibernateProxyHelper.deproxy(gesamtListeTaxon.clone(), Taxon.class);
182 }
183 else if(gesamtListeTaxon.isInstanceOf(Synonym.class)){
184 clonedTaxon = Taxon.NewInstance(gesamtListeTaxon.getName(), gesamtListeTaxon.getSec());
185 }
186 else{
187 RedListUtil.logMessage(id, "Taxon base "+gesamtListeTaxon+" is neither taxon nor synonym! Taxon could not be cloned", logger);
188 return;
189 }
190 ImportHelper.setOriginalSource(clonedTaxon, state.getTransactionalSourceReference(), id, sourceNameSpace);
191 taxaToSave.add(clonedTaxon);
192 }
193 }
194
195 private TaxonBase<?> importTaxon(ResultSet rs, NonViralName<?> name, RedListGefaesspflanzenImportState state) throws SQLException {
196
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);
212
213 TaxonBase<?> taxonBase = null;
214 if(authorBasiString.trim().contains(RedListUtil.AUCT)){
215 taxonBase = Taxon.NewInstance(name, null);
216 taxonBase.setAppendedPhrase(RedListUtil.AUCT);
217 }
218 else if(gueltString.equals(RedListUtil.GUELT_ACCEPTED_TAXON)){
219 taxonBase = Taxon.NewInstance(name, null);
220 }
221 else if(gueltString.equals(RedListUtil.GUELT_SYNONYM) || gueltString.equals(RedListUtil.GUELT_BASIONYM)){
222 taxonBase = Synonym.NewInstance(name, null);
223 }
224 else{
225 return null;
226 }
227
228 //common name
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()));
233 }
234
235 //add annotations
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);
242
243 //check taxon name consistency
244 checkTaxonConsistency(id, taxNameString, hybString, epi1String, epi2String, epi3String, taxonBase, state);
245 return taxonBase;
246 }
247
248 private void addAnnotation(String string, AnnotatableEntity entity) {
249 if(CdmUtils.isNotBlank(string)){
250 entity.addAnnotation(Annotation.NewInstance(string, AnnotationType.TECHNICAL(), Language.GERMAN()));
251 }
252 }
253
254 private void importAuthors(RedListGefaesspflanzenImportState state, ResultSet rs, NonViralName<?> name) throws SQLException {
255
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);
263
264 //combination author
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);
276 }
277 else if(authorKombString.trim().contains(RedListUtil.AUCT)){
278 RedListUtil.logMessage(id, "AUCT information in "+RedListUtil.AUTOR_KOMB+" column", logger);
279 }
280 else if(CdmUtils.isNotBlank(authorKombString)){
281 TeamOrPersonBase<?> authorKomb = (TeamOrPersonBase<?>) state.getRelatedObject(RedListUtil.AUTHOR_NAMESPACE, authorKombString);
282 name.setCombinationAuthorship(authorKomb);
283 }
284 //basionym author
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);
289 }
290 else{
291 name.setExBasionymAuthorship(authorExBasi);
292 }
293 TeamOrPersonBase<?> authorBasi= (TeamOrPersonBase<?>) state.getRelatedObject(RedListUtil.AUTHOR_NAMESPACE, RedListUtil.getAuthorOfExAuthorshipString(authorBasiString));
294 if(CdmUtils.isBlank(authorKombString)){
295 name.setCombinationAuthorship(authorBasi);
296 }
297 else{
298 name.setBasionymAuthorship(authorBasi);
299 }
300 }
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);
306 }
307 else{
308 name.setBasionymAuthorship(authorBasi);
309 }
310 }
311
312 //check authorship consistency
313 String authorString = rs.getString(RedListUtil.AUTOR);
314 checkNameConsistency(id, nomZusatzString, taxZusatzString, zusatzString, authorString, hybString, name);
315 }
316
317 private NonViralName<?> importName(RedListGefaesspflanzenImportState state, ResultSet rs, Set<TaxonNameBase> namesToSave) throws SQLException {
318
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);
328
329 if(CdmUtils.isBlank(taxNameString) && CdmUtils.isBlank(ep1String)){
330 RedListUtil.logMessage(id, "No name found!", logger);
331 }
332
333 NonViralName<?> name = null;
334 Rank rank = makeRank(id, state, rangString, CdmUtils.isNotBlank(ep3String));
335 //cultivar
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);
341 name = cultivar;
342 }
343 //botanical names
344 else{
345 name = BotanicalName.NewInstance(rank);
346
347 //ep1 should always be present
348 if(CdmUtils.isBlank(ep1String)){
349 RedListUtil.logMessage(id, RedListUtil.EPI1+" is empty!", logger);
350 }
351 name.setGenusOrUninomial(ep1String);
352 if(CdmUtils.isNotBlank(ep2String)){
353 if(rank!=null && rank.isInfraGenericButNotSpeciesGroup()){
354 name.setInfraGenericEpithet(ep2String);
355 }
356 else{
357 name.setSpecificEpithet(ep2String);
358 }
359 }
360 if(CdmUtils.isNotBlank(ep3String)){
361 name.setInfraSpecificEpithet(ep3String);
362 }
363
364
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);
375 if (matcher.find()){
376 status.setRuleConsidered(matcher.group(1));
377 }
378 }
379 name.addStatus(status);
380 }
381 }
382 //hybrid
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);
389 }
390 else if(hybString.equals(RedListUtil.HYB_X)){
391 name.setBinomHybrid(true);
392 }
393 else if(hybString.equals(RedListUtil.HYB_G)){
394 name.setMonomHybrid(true);
395 }
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);
400 }
401 else if(hybString.equals(RedListUtil.HYB_N)){
402 name = NonViralNameParserImpl.NewInstance().parseFullName(taxNameString, NomenclaturalCode.ICNAFP, rank);
403 }
404 else if(hybString.equals(RedListUtil.HYB_GF)){
405 if(ep1String.contains(RedListUtil.HYB_SIGN)){
406 name = NonViralNameParserImpl.NewInstance().parseFullName(ep1String, NomenclaturalCode.ICNAFP, rank);
407 }
408 else{
409 RedListUtil.logMessage(id, "HYB is "+hybString+" but "+RedListUtil.HYB+" does not contain "+RedListUtil.HYB_SIGN, logger);
410 }
411 }
412 else if(hybString.equals(RedListUtil.HYB_XS)){
413 //nothing to do
414 }
415 else{
416 logger.error("HYB value "+hybString+" not yet handled");
417 }
418 //save hybrid formula
419 if(CdmUtils.isNotBlank(formelString)){
420 Annotation annotation = Annotation.NewDefaultLanguageInstance(formelString);
421 annotation.setAnnotationType(AnnotationType.TECHNICAL());
422 name.addAnnotation(annotation);
423 }
424 }
425 }
426
427 //add source
428 ImportHelper.setOriginalSource(name, state.getTransactionalSourceReference(), id, RedListUtil.NAME_NAMESPACE);
429
430 namesToSave.add(name);
431 return name;
432 }
433
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;
438 }
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);
448 }
449 else if(secondHybrid.length>1 && secondHybrid[0].matches("[A-Z].*")){
450 hybridFormula2 = split[1].trim();
451 }
452 if(CdmUtils.isNotBlank(ep3String)){
453 hybridFormula1 += " "+rank.getAbbreviation()+" "+ep3String;
454 hybridFormula2 += " "+rank.getAbbreviation()+" "+ep3String;
455 }
456 fullFormula = hybridFormula1+" "+RedListUtil.HYB_SIGN+" "+hybridFormula2;
457 }
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);
467 }
468 else if(secondHybrid.length>1 && secondHybrid[0].matches("[A-Z].*")){
469 hybridFormula2 = split[1].trim();
470 }
471 fullFormula = hybridFormula1+" "+RedListUtil.HYB_SIGN+" "+hybridFormula2;
472 }
473 return fullFormula;
474 }
475
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);
483 return;
484 }
485 return;
486 }
487
488 if(CdmUtils.isNotBlank(zusatzString)){
489 authorString = authorString.replace(", "+zusatzString, "");
490 }
491 if(CdmUtils.isNotBlank(nomZusatzString)){
492 authorString = authorString.replace(", "+nomZusatzString, "");
493 }
494 if(CdmUtils.isNotBlank(taxZusatzString)){
495 authorString = authorString.replace(", "+taxZusatzString, "");
496 }
497 if(authorString.equals(RedListUtil.AUCT)){
498 authorString = "";
499 }
500 if(authorString.contains(RedListUtil.EX)){
501 String exAuthor = RedListUtil.getExAuthorOfExAuthorshipString(authorString);
502 String author = RedListUtil.getAuthorOfExAuthorshipString(authorString);
503 authorString = exAuthor+RedListUtil.EX+author;
504 }
505 if(STRICT_TITLE_CHECK){
506 if(!authorString.equals(authorshipCache)){
507 RedListUtil.logMessage(id, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil.AUTOR+": "+authorshipCache+" <-> "+authorString, logger);
508 }
509 }
510 else{
511 if(CdmUtils.isNotBlank(authorString) && !authorString.startsWith(authorshipCache)){
512 RedListUtil.logMessage(id, "Authorship inconsistent! name.authorhshipCache <-> Column "+RedListUtil.AUTOR+": "+authorshipCache+" <-> "+authorString, logger);
513 }
514 }
515 }
516
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);
520 return;
521 }
522
523 String nameCache = HibernateProxyHelper.deproxy(taxonBase.getName(), NonViralName.class).getNameCache().trim();
524 taxNameString = taxNameString.trim();
525 taxNameString = taxNameString.replaceAll(" +", " ");
526
527
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
531 }
532 else if(hybString.equals(RedListUtil.HYB_G)){
533 taxNameString = taxNameString.replace("X ", RedListUtil.HYB_SIGN);
534 }
535 else if(hybString.equals(RedListUtil.HYB_GF)){
536 taxNameString = taxNameString.replace(" "+RedListUtil.HYB_SIGN+" ", " "+RedListUtil.HYB_SIGN);
537 }
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"));
542 }
543 if(!STRICT_TITLE_CHECK){
544 taxNameString = buildHybridFormula(epi1String, epi2String, epi3String, taxonBase.getName().getRank());
545 }
546 if(taxNameString.split(RedListUtil.HYB_SIGN).length==1){
547 taxNameString = taxNameString.replace(RedListUtil.HYB_SIGN+" ", RedListUtil.HYB_SIGN);
548 }
549 }
550
551 if(taxNameString.endsWith("- Gruppe")){
552 taxNameString = taxNameString.replaceAll("- Gruppe", "species group");
553 }
554 if(taxNameString.endsWith("- group")){
555 taxNameString = taxNameString.replaceAll("- group", "species group");
556 }
557
558 taxNameString = taxNameString.replace("agg.", "aggr.");
559 taxNameString = taxNameString.replace("[ranglos]", "[unranked]");
560
561 if(taxonBase.getName().getRank()!=null){
562 if(taxonBase.getName().getRank().equals(Rank.PROLES())){
563 taxNameString = taxNameString.replace("proles", "prol.");
564 }
565 else if(taxonBase.getName().getRank().equals(state.getRank(RedListUtil.uuidRankCollectionSpecies))){
566 taxNameString = taxNameString.replace("\"Sammelart\"", "\"Coll. Species\"");
567 }
568 }
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);
572 }
573 }
574 else{
575 if(!taxNameString.startsWith(nameCache)){
576 RedListUtil.logMessage(id, "Taxon name inconsistent! taxon.nameCache <-> Column "+RedListUtil.TAXNAME+": "+nameCache+" <-> "+taxNameString, logger);
577 }
578 }
579 }
580
581 private Rank makeRank(long id, RedListGefaesspflanzenImportState state, String rankStr, boolean hasSpecificEpithet) {
582 Rank rank = null;
583 try {
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);
589 }
590 else{
591 return Rank.UNRANKED_INFRAGENERIC();
592 }
593 }
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);
596 }
597 else if(rankStr.equals("SPR")){
598 return getRank(state, RedListUtil.uuidRankSubproles, "Subproles", "Subproles", "subproles", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
599 }
600 else if(rankStr.equals("MOD")){
601 return getRank(state, RedListUtil.uuidRankModification, "Modification", "Modification", "modificatio", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
602 }
603 else if(rankStr.equals("LUS")){
604 return getRank(state, RedListUtil.uuidRankLusus, "Lusus", "Lusus", "lusus", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
605 }
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);
608 }
609 else if(rankStr.equals("KMB")){
610 return getRank(state, RedListUtil.uuidRankCombination, "Combination", "Combination", "", (OrderedTermVocabulary<Rank>) Rank.GENUS().getVocabulary(), null, RankClass.Infraspecific);
611 }
612 else{
613 rank = state.getTransformer().getRankByKey(rankStr);
614 }
615 } catch (UndefinedTransformerMethodException e) {
616 e.printStackTrace();
617 }
618 if(rank==null){
619 RedListUtil.logMessage(id, rankStr+" could not be associated to a known rank.", logger);
620 }
621 return rank;
622 }
623
624 private NomenclaturalStatusType makeNomenclaturalStatus(long id, RedListGefaesspflanzenImportState state, String nomZusatzString) {
625 NomenclaturalStatusType status = null;
626 try {
627 status = state.getTransformer().getNomenclaturalStatusByKey(nomZusatzString);
628 } catch (UndefinedTransformerMethodException e) {
629 e.printStackTrace();
630 }
631 if(status==null){
632 RedListUtil.logMessage(id, nomZusatzString+" could not be associated to a known nomenclatural status.", logger);
633 }
634 return status;
635 }
636
637
638
639 @Override
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<?>>();
644
645 try {
646 while (rs.next()){
647 String authorKombString = rs.getString(RedListUtil.AUTOR_KOMB);
648
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])));
654 }
655 }
656 }
657 else if(CdmUtils.isNotBlank(authorKombString) && !authorMap.containsKey(authorKombString)){
658 authorMap.put(authorKombString, getAgentService().load(state.getAuthorMap().get(authorKombString)));
659 }
660
661 String authorBasiString = rs.getString(RedListUtil.AUTOR_BASI);
662 //basionym author
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])));
668 }
669 }
670 }
671 else if(CdmUtils.isNotBlank(authorBasiString) && !authorMap.containsKey(authorBasiString)){
672 authorMap.put(authorBasiString, getAgentService().load(state.getAuthorMap().get(authorBasiString)));
673 }
674 }
675 } catch (SQLException e) {
676 e.printStackTrace();
677 }
678 result.put(RedListUtil.AUTHOR_NAMESPACE, authorMap);
679
680 return result;
681 }
682
683 @Override
684 protected boolean doCheck(RedListGefaesspflanzenImportState state) {
685 return false;
686 }
687
688 @Override
689 protected boolean isIgnore(RedListGefaesspflanzenImportState state) {
690 return false;
691 }
692
693 }