1
2
3
4
5
6
7
8
9 package eu.etaxonomy.cdm.io.taxonx;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import javax.naming.NameParser;
18
19 import org.apache.log4j.Logger;
20 import org.jdom.Element;
21 import org.jdom.Namespace;
22 import org.springframework.stereotype.Component;
23 import org.springframework.transaction.TransactionStatus;
24
25 import eu.etaxonomy.cdm.api.service.ICommonService;
26 import eu.etaxonomy.cdm.api.service.INameService;
27 import eu.etaxonomy.cdm.api.service.ITaxonService;
28 import eu.etaxonomy.cdm.api.service.pager.Pager;
29 import eu.etaxonomy.cdm.common.CdmUtils;
30 import eu.etaxonomy.cdm.io.common.CdmIoBase;
31 import eu.etaxonomy.cdm.io.common.ICdmIO;
32 import eu.etaxonomy.cdm.io.common.IImportConfigurator;
33 import eu.etaxonomy.cdm.model.agent.AgentBase;
34 import eu.etaxonomy.cdm.model.agent.Person;
35 import eu.etaxonomy.cdm.model.common.CdmBase;
36 import eu.etaxonomy.cdm.model.name.NameTypeDesignationStatus;
37 import eu.etaxonomy.cdm.model.name.NonViralName;
38 import eu.etaxonomy.cdm.model.name.Rank;
39 import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignationStatus;
40 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
41 import eu.etaxonomy.cdm.model.occurrence.Specimen;
42 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
43 import eu.etaxonomy.cdm.model.taxon.Synonym;
44 import eu.etaxonomy.cdm.model.taxon.Taxon;
45 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
46 import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
47
48
49
50
51
52
53
54 @Component
55 public class TaxonXNomenclatureImport extends CdmIoBase<TaxonXImportState> implements ICdmIO<TaxonXImportState> {
56 private static final Logger logger = Logger.getLogger(TaxonXNomenclatureImport.class);
57
58 @SuppressWarnings("unused")
59 private static int modCount = 10000;
60
61 public TaxonXNomenclatureImport(){
62 super();
63 }
64
65 public boolean doCheck(TaxonXImportState state){
66 boolean result = true;
67 logger.warn("Checking for Types not yet implemented");
68
69
70
71 return result;
72 }
73
74 public boolean doInvoke(TaxonXImportState state){
75 logger.info("start make Nomenclature ...");
76 TransactionStatus tx = startTransaction();
77 TaxonXImportConfigurator config = state.getConfig();
78 Element root = config.getSourceRoot();
79 Namespace nsTaxonx = root.getNamespace();
80
81
82 Taxon taxon = getTaxon(config);
83 boolean isChanged = false;
84
85 Element elTaxonBody = root.getChild("taxonxBody", nsTaxonx);
86 Element elTreatment = elTaxonBody.getChild("treatment", nsTaxonx);
87 Element elNomenclature = elTreatment.getChild("nomenclature", nsTaxonx);
88
89
90
91 if (taxon != null && taxon.getName() != null && elNomenclature != null){
92 isChanged |= doNomenclaturalType(config, elNomenclature, nsTaxonx, taxon.getName());
93 List<Element> elSynonymyList = new ArrayList<Element>();
94 elSynonymyList.addAll(elNomenclature.getChildren("synonomy", nsTaxonx));
95 elSynonymyList.addAll(elNomenclature.getChildren("synonymy", nsTaxonx));
96 for (Element elSynonymy : elSynonymyList){
97 String synonymName = elSynonymy.getChildTextTrim("name");
98 if (elSynonymy.getChild("type", nsTaxonx) != null || elSynonymy.getChild("type_loc", nsTaxonx) != null){
99 Synonym synonym = getSynonym(config, taxon, synonymName);
100 if (synonym != null){
101 isChanged |= doNomenclaturalType(config, elSynonymy, nsTaxonx, synonym.getName());
102 }
103 }
104 }
105 }
106
107
108 if (isChanged){
109 getTaxonService().save(taxon);
110 }
111 commitTransaction(tx);
112 return true;
113 }
114
115 private Synonym getSynonym(TaxonXImportConfigurator config, Taxon taxon, String synName){
116 Synonym result = null;
117 unlazySynonym(config, taxon);
118 Set<Synonym> synList = taxon.getSynonyms();
119 for (Synonym syn : synList){
120 TaxonNameBase<?,?> nameBase = syn.getName();
121 if (nameBase != null){
122 if (nameBase.isInstanceOf(NonViralName.class)){
123 NonViralName<?> nonViralName = nameBase.deproxy(nameBase, NonViralName.class);
124 if (nonViralName.getNameCache().equals(synName)){
125 return syn;
126 }
127 }
128 }
129 }
130 logger.warn("Synonym ("+synName+ ")not found for taxon " + taxon.getTitleCache() + getBracketSourceName(config));
131 return result;
132 }
133
134 private Taxon getTaxon(TaxonXImportConfigurator config){
135 Taxon result;
136
137
138 ICommonService commonService = getCommonService();
139 String originalSourceId = config.getOriginalSourceId();
140 String namespace = config.getOriginalSourceTaxonNamespace();
141 result = (Taxon)commonService.getSourcedObjectByIdInSource(Taxon.class, originalSourceId , namespace);
142 if (result == null){
143 logger.warn("Taxon (id: " + originalSourceId + ", namespace: " + namespace + ") could not be found");
144 }
145 return result;
146 }
147
148
149
150
151 protected boolean isIgnore(TaxonXImportState state){
152 return ! state.getConfig().isDoTypes();
153 }
154
155
156
157
158
159
160
161
162
163
164 private boolean doNomenclaturalType(TaxonXImportConfigurator config, Element elNomenclature, Namespace nsTaxonx, TaxonNameBase taxonName){
165 boolean success = true;
166 if (taxonName == null){
167 logger.warn("taxonName is null");
168 return false;
169 }
170 if (elNomenclature == null){
171 logger.warn("elNomenclature is null");
172 return false;
173 }
174
175
176 Element elType = elNomenclature.getChild("type", nsTaxonx);
177 Element elTypeLoc = elNomenclature.getChild("type_loc", nsTaxonx);
178
179 if (elType != null || elTypeLoc != null){
180 unlazyTypeDesignation(config, taxonName);
181
182 if (taxonName.isInfraGeneric() || taxonName.isSupraGeneric() || taxonName.isGenus()){
183 success &= doNameType(elType, taxonName, config);
184 }else{
185 success &= doSpecimenType(config, elType, elTypeLoc, taxonName);
186
187
188 }
189 return success;
190 }
191 return false;
192 }
193
194
195 private boolean doSpecimenType(TaxonXImportConfigurator config, Element elType, Element elTypeLoc, TaxonNameBase taxonName){
196 ReferenceBase citation = null;
197 String citationMicroReference = null;
198 String originalNameString = null;
199 boolean isNotDesignated = true;
200 boolean addToAllHomotypicNames = true;
201
202 SimpleSpecimen simpleSpecimen = SimpleSpecimen.NewInstance();
203
204 if (elType != null){
205 doElType(elType, simpleSpecimen, config);
206 }
207
208
209 HashMap<Specimen, SpecimenTypeDesignationStatus> typeLocMap = null;
210 if (elTypeLoc != null){
211 typeLocMap = doElTypeLoc(elTypeLoc, simpleSpecimen, taxonName, config);
212 }
213 if (typeLocMap != null && typeLocMap.size() >0){
214 for (Specimen specimen : typeLocMap.keySet()){
215 SpecimenTypeDesignationStatus status = typeLocMap.get(specimen);
216 taxonName.addSpecimenTypeDesignation(specimen, status, citation, citationMicroReference, originalNameString, isNotDesignated, addToAllHomotypicNames);
217 }
218 }else{
219 SpecimenTypeDesignationStatus status = null;
220 taxonName.addSpecimenTypeDesignation(simpleSpecimen.getSpecimen(), status, citation, citationMicroReference, originalNameString, isNotDesignated, addToAllHomotypicNames);
221 }
222 return true;
223 }
224
225 private boolean doElType(Element elType, SimpleSpecimen simpleSpecimen, TaxonXImportConfigurator config){
226
227 String text = elType.getTextNormalize();
228 if (text.endsWith(";")){
229 text = text + " ";
230 }
231 String[] type = text.split(";");
232 if (type.length != 3 ){
233 if (text.equals("")){
234 logger.info("<nomenclature><type> is empty: " + getBracketSourceName(config));
235 }else{
236 logger.warn("<nomenclature><type> is of unsupported format: " + elType.getTextNormalize() + getBracketSourceName(config));
237 }
238 simpleSpecimen.setTitleCache(elType.getTextNormalize());
239 }else{
240 String strLocality = type[0].trim();
241 if (! "".equals(strLocality)){
242
243 }
244
245 String strCollector = type[1].trim();
246 if (! "".equals(strCollector)){
247 AgentBase collector = Person.NewTitledInstance(strCollector);
248
249 }
250
251 String strCollectorNumber = type[2].trim();
252 if (! "".equals(strCollectorNumber)){
253
254 }
255
256 String title = CdmUtils.concat(" ", new String[]{strLocality, strCollector, strCollectorNumber});
257 simpleSpecimen.setTitleCache(title);
258 }
259 return true;
260 }
261
262 private boolean doNameType(Element elType, TaxonNameBase taxonName, TaxonXImportConfigurator config){
263 boolean success = true;
264
265 String text = elType.getTextNormalize();
266 logger.info("Type: " + text);
267 if (text.endsWith(";")){
268 text = text + " ";
269 }
270 String[] type = text.split(";");
271 if (type.length != 3 ){
272 if (text.equals("")){
273 logger.info("<nomenclature><type> is empty: " + getBracketSourceName(config));
274 }else{
275 logger.warn("<nomenclature><type> is of unsupported format: " + elType.getTextNormalize() + getBracketSourceName(config));
276 }
277 success = false;
278 }else{
279 String statusStr = type[0].trim();
280 String taxonNameStr = type[1].trim();
281 String authorStr = type[2].trim();
282 NameTypeDesignationStatus status = getNameTypeStatus(statusStr);
283
284
285
286
287
288
289
290
291
292
293 String[] epis = taxonNameStr.split(" ");
294 String uninomial = epis[0].trim();
295 String specEpi = epis[1].trim();
296
297 Pager<TaxonNameBase> nameTypes = getNameService().searchNames(uninomial, null, specEpi, null, Rank.SPECIES(), null, null, null, null);
298
299 List<NonViralName> result = new ArrayList<NonViralName>();
300 for (TaxonNameBase nt : nameTypes.getRecords()){
301 NonViralName nameType = CdmBase.deproxy(nt, NonViralName.class);
302 if (compareAuthorship(nameType, authorStr)){
303 result.add(nameType);
304 success &= doNameTypeDesignation(taxonName, nameType, status
305 }else{
306 success = success;
307 }
308 }
309 if (result.size() > 1){
310 logger.warn("More than 1 name matches: " + text);
311 success = false;
312 }else if (result.size() == 0){
313 logger.warn("No name matches: " + text + "(" + config.getSourceNameString() + ")");
314 success = false;
315 }
316
317
318 }
319 return success;
320 }
321
322
323 private TaxonNameBase getChildrenNameType(TaxonNameBase name, String typeStr, String authorStr){
324 TaxonNameBase result = null;
325 Set<TaxonBase> list = name.getTaxonBases();
326 for (TaxonBase taxonBase : list){
327 Taxon taxon;
328 if (taxonBase.isInstanceOf(Taxon.class)){
329 taxon = CdmBase.deproxy(taxonBase, Taxon.class);
330 }else{
331 Synonym syn = CdmBase.deproxy(taxonBase, Synonym.class);
332 taxon = syn.getAcceptedTaxa().iterator().next();
333 }
334 Set<Taxon> children = taxon.getTaxonomicChildren();
335 for (Taxon child: children){
336 NonViralName childName = (CdmBase.deproxy(child.getName(), NonViralName.class));
337 if (childName.getNameCache().equals(typeStr)){
338 if (compareAuthorship(childName, authorStr)){
339 return childName;
340 }
341 }
342 }
343 }
344 return result;
345 }
346
347 private boolean compareAuthorship(NonViralName typeName, String authorStr){
348 boolean result = false;
349 authorStr = authorStr.replaceAll("\\s+and\\s+", "&");
350 authorStr = authorStr.replaceAll("\\s*", "");
351 authorStr = authorStr.replaceAll("\\.$", "");
352 String typeCache = typeName.getAuthorshipCache().replaceAll("\\s*", "");
353 typeCache = typeCache.replaceAll("\\.$", "");
354 if (authorStr.equals(typeCache)){
355 return true;
356 }else{
357 logger.info(" Authors different: " + authorStr + " <-> " + typeCache);
358 }
359 return result;
360 }
361
362 private NameTypeDesignationStatus getNameTypeStatus(String statusString){
363
364 if (true){
365 return null;
366 }
367 if (statusString.trim().equalsIgnoreCase("Type")){
368 return NameTypeDesignationStatus.ORIGINAL_DESIGNATION();
369 }else if (statusString.trim().equalsIgnoreCase("Lectotype")){
370 return NameTypeDesignationStatus.LECTOTYPE();
371 }else if (statusString.trim().equalsIgnoreCase("Holotype")){
372 logger.warn("Holotype does not yet exist in CDM");
373 return NameTypeDesignationStatus.NOT_APPLICABLE();
374 }else if (statusString.trim().equalsIgnoreCase("paratype")){
375 logger.warn("paratype does not yet exist in CDM");
376 return NameTypeDesignationStatus.NOT_APPLICABLE();
377 }
378 else{
379 logger.warn("Status not recognized: " + statusString);
380 return null;
381 }
382 }
383
384 private boolean getIsLectoType(String statusString){
385
386 if (statusString.trim().equals("Lectotype")){
387 return true;
388 }else{
389 return false;
390 }
391 }
392
393
394 private boolean doNameTypeDesignation(TaxonNameBase name, TaxonNameBase type, NameTypeDesignationStatus status
395 ReferenceBase citation = null;
396 String citationMicroReference = null;
397 String originalNameString = null;
398 boolean addToAllHomotypicNames = true;
399
400
401 name.addNameTypeDesignation(type, citation, citationMicroReference, originalNameString,status, false, false,
402 return true;
403 }
404
405
406
407
408
409
410
411
412
413 private HashMap<Specimen, SpecimenTypeDesignationStatus> doElTypeLoc(Element elTypeLoc,
414 SimpleSpecimen simpleSpecimen,
415 TaxonNameBase<?,?> taxonName,
416 TaxonXImportConfigurator config){
417
418 HashMap<Specimen, SpecimenTypeDesignationStatus> result = new HashMap<Specimen, SpecimenTypeDesignationStatus>();
419
420 String typeLocFullString = elTypeLoc.getTextTrim();
421 typeLocFullString = typeLocFullString.replace("(", "").replace(")", "");
422 String[] typeLocStatusList = typeLocFullString.split(";");
423
424 Specimen originalSpecimen = simpleSpecimen.getSpecimen();
425
426
427 for (String typeLocStatus : typeLocStatusList){
428 typeLocStatus = typeLocStatus.trim();
429 int pos = typeLocStatus.indexOf(" ");
430 if (pos == -1){
431 logger.warn("Unknown format or empty type_loc : '" +typeLocStatus + "'" + getBracketSourceName(config));
432 result.put(originalSpecimen, null);
433 }else{
434 String statusString = typeLocStatus.substring(0,pos);
435 SpecimenTypeDesignationStatus status = getStatusByStatusString(statusString.trim(), config);
436
437
438 String tmpCollString = typeLocStatus.substring(pos).trim();
439
440 if (tmpCollString.contains("typ")){
441 logger.warn("Is this really only a collection string? : " + tmpCollString + getBracketSourceName(config));
442 }
443 Specimen specimen;
444 specimen = (Specimen)originalSpecimen.clone();
445 String title = originalSpecimen.getTitleCache();
446 title = title + "(" + tmpCollString + ")";
447 specimen.setTitleCache(title, true );
448 result.put(specimen, status);
449
450 }
451 }
452
453 return result;
454 }
455
456
457
458
459
460
461
462
463
464
465 private boolean doCollectionEvent(TaxonXImportConfigurator config, Element elNomenclature, Namespace nsTaxonx, TaxonBase taxonBase){
466 boolean result = false;
467 if (elNomenclature == null){
468 return false;
469 }
470 Element elCollectionEvent = elNomenclature.getChild("collection_event", nsTaxonx);
471 if (elCollectionEvent == null){
472 return result;
473 }
474 Element elLocality = elCollectionEvent.getChild("locality", nsTaxonx);
475 Element elType = elCollectionEvent.getChild("type", nsTaxonx);
476 Element elTypeLoc = elCollectionEvent.getChild("type_loc", nsTaxonx);
477
478
479 SimpleSpecimen simpleSpecimen = SimpleSpecimen.NewInstance();
480 String locality = elLocality.getTextNormalize();
481 if (! "".equals(locality)){
482 simpleSpecimen.setLocality(locality);
483 }
484
485
486 String[] type = elType.getTextNormalize().split(" ");
487 if (type.length != 2 ){
488 logger.warn("<collecion_even><type> is of unsupported format: " + elType.getTextNormalize());
489 }else{
490 AgentBase collector = Person.NewTitledInstance(type[0]);
491 simpleSpecimen.setCollector(collector);
492
493 String collectorNumber = type[1];
494 simpleSpecimen.setCollectorsNumber(collectorNumber);
495 }
496
497
498 String typeLocFullString = elTypeLoc.getTextTrim();
499 typeLocFullString = typeLocFullString.replace("(", "").replace(")", "");
500 String[] typeLocStatusList = typeLocFullString.split(";");
501
502 Specimen originalSpecimen = simpleSpecimen.getSpecimen();
503
504
505
506 for (String typeLocStatus : typeLocStatusList){
507 typeLocStatus = typeLocStatus.trim();
508 int pos = typeLocStatus.indexOf(" ");
509 if (pos == -1){
510 logger.warn("Unknown format: " + typeLocStatus);
511 }else{
512 String statusString = typeLocStatus.substring(0,pos);
513 SpecimenTypeDesignationStatus status = getStatusByStatusString(statusString.trim(), config);
514 String[] collectionStrings = typeLocStatus.substring(pos).split(",");
515 for(String collectionString : collectionStrings){
516 if (taxonBase != null){
517 TaxonNameBase<?, ?> taxonName = taxonBase.getName();
518 if (taxonName != null){
519 ReferenceBase citation = null;
520 String citationMicroReference = null;
521 String originalNameString = null;
522 boolean isNotDesignated = true;
523 boolean addToAllHomotypicNames = true;
524 Specimen specimen = (Specimen)originalSpecimen.clone();
525 unlazyTypeDesignation(config, taxonName);
526 taxonName.addSpecimenTypeDesignation(specimen, status, citation, citationMicroReference, originalNameString, isNotDesignated, addToAllHomotypicNames);
527 result = true;
528 }
529 }
530 }
531 }
532 }
533 return result;
534 }
535
536
537 private static Map<String, SpecimenTypeDesignationStatus> statusMap;
538 private static void fillTypeStatusMap(){
539 statusMap = new HashMap<String, SpecimenTypeDesignationStatus>();
540 statusMap.put("epitype", SpecimenTypeDesignationStatus.EPITYPE());
541 statusMap.put("holotype", SpecimenTypeDesignationStatus.HOLOTYPE());
542 statusMap.put("iconotype", SpecimenTypeDesignationStatus.ICONOTYPE());
543 statusMap.put("isotype", SpecimenTypeDesignationStatus.ISOTYPE());
544 statusMap.put("isoneotype", SpecimenTypeDesignationStatus.ISONEOTYPE());
545 statusMap.put("isosyntype", SpecimenTypeDesignationStatus.ISOSYNTYPE());
546 statusMap.put("isolectotype", SpecimenTypeDesignationStatus.ISOLECTOTYPE());
547 statusMap.put("lectotype", SpecimenTypeDesignationStatus.LECTOTYPE());
548 statusMap.put("syntype", SpecimenTypeDesignationStatus.SYNTYPE());
549 statusMap.put("paratype", SpecimenTypeDesignationStatus.PARATYPE());
550 statusMap.put("neotype", SpecimenTypeDesignationStatus.NEOTYPE());
551 statusMap.put("isoepitype", SpecimenTypeDesignationStatus.ISOEPITYPE());
552 statusMap.put("originalmaterial", SpecimenTypeDesignationStatus.ORIGINAL_MATERIAL());
553 statusMap.put("paralectotype", SpecimenTypeDesignationStatus.PARALECTOTYPE());
554 statusMap.put("paraneotype", SpecimenTypeDesignationStatus.PARANEOTYPE());
555 statusMap.put("phototype", SpecimenTypeDesignationStatus.PHOTOTYPE());
556 statusMap.put("secondsteplectotype", SpecimenTypeDesignationStatus.SECOND_STEP_LECTOTYPE());
557 statusMap.put("secondstepneotype", SpecimenTypeDesignationStatus.SECOND_STEP_NEOTYPE());
558 statusMap.put("type", null);
559 }
560
561
562
563
564
565
566
567
568 private static SpecimenTypeDesignationStatus getStatusByStatusString(String statusString, TaxonXImportConfigurator config){
569 SpecimenTypeDesignationStatus result = null;
570 if (statusString == null || "".equals(statusString.trim())){
571 return null;
572 }
573 statusString = statusString.trim().toLowerCase();
574 statusString = statusString.replace("typi", "typus");
575 statusString = statusString.replace("typus", "type");
576 statusString = statusString.replace("types", "type");
577 statusString = statusString.toLowerCase();
578
579 if (statusMap == null){
580 fillTypeStatusMap();
581 }
582 result = statusMap.get(statusString);
583 if (statusString.equals("type")){
584 logger.info("No type designation type" + getBracketSourceName(config));
585 }else if (result == null){
586 logger.warn("Unknown type status string: " + statusString + getBracketSourceName(config));
587 }
588 return result;
589 }
590
591
592
593
594
595 private void unlazyTypeDesignation(TaxonXImportConfigurator config, TaxonNameBase taxonNameBase){
596 TransactionStatus txStatus = startTransaction();
597
598 INameService taxonNameService = getNameService();
599
600 taxonNameService.save(taxonNameBase);
601 Set<TaxonNameBase> typifiedNames = taxonNameBase.getHomotypicalGroup().getTypifiedNames();
602 for(TaxonNameBase typifiedName: typifiedNames){
603 typifiedName.getTypeDesignations().size();
604 }
605
606 commitTransaction(txStatus);
607 }
608
609
610
611
612 private void unlazySynonym(IImportConfigurator config, Taxon taxon){
613 TransactionStatus txStatus = startTransaction();
614 ITaxonService taxonService = getTaxonService();
615 taxonService.save(taxon);
616 Set<Synonym> synonyms = taxon.getSynonyms();
617 logger.debug(synonyms.size());
618
619 commitTransaction(txStatus);
620 }
621
622 private static String getBracketSourceName(TaxonXImportConfigurator config){
623 return "(" + config.getSourceNameString() + ")";
624 }
625
626
627 }