ref #6794 reduce calls to isLower and isHigher in Rank class in app-import
[cdmlib-apps.git] / app-import / src / main / java / eu / etaxonomy / cdm / io / redlist / bfnXml / out / BfnXmlTaxonNameExport.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.bfnXml.out;
10
11 import java.util.Comparator;
12 import java.util.List;
13 import java.util.Set;
14 import java.util.UUID;
15
16 import org.apache.logging.log4j.LogManager;
17 import org.apache.logging.log4j.Logger;
18 import org.jdom2.Attribute;
19 import org.jdom2.Document;
20 import org.jdom2.Element;
21 import org.springframework.stereotype.Component;
22
23 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
24 import eu.etaxonomy.cdm.io.redlist.bfnXml.BfnXmlConstants;
25 import eu.etaxonomy.cdm.io.redlist.bfnXml.in.BfnXmlTransformer;
26 import eu.etaxonomy.cdm.model.common.ExtensionType;
27 import eu.etaxonomy.cdm.model.common.IdentifiableSource;
28 import eu.etaxonomy.cdm.model.common.Language;
29 import eu.etaxonomy.cdm.model.description.CategoricalData;
30 import eu.etaxonomy.cdm.model.description.CommonTaxonName;
31 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
32 import eu.etaxonomy.cdm.model.description.Feature;
33 import eu.etaxonomy.cdm.model.description.State;
34 import eu.etaxonomy.cdm.model.description.StateData;
35 import eu.etaxonomy.cdm.model.description.TaxonDescription;
36 import eu.etaxonomy.cdm.model.description.TextData;
37 import eu.etaxonomy.cdm.model.name.INonViralName;
38 import eu.etaxonomy.cdm.model.name.Rank;
39 import eu.etaxonomy.cdm.model.name.RankClass;
40 import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
41 import eu.etaxonomy.cdm.model.taxon.Classification;
42 import eu.etaxonomy.cdm.model.taxon.Synonym;
43 import eu.etaxonomy.cdm.model.taxon.Taxon;
44 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
45 import eu.etaxonomy.cdm.model.taxon.TaxonNode;
46 import eu.etaxonomy.cdm.model.term.DefinedTerm;
47 import eu.etaxonomy.cdm.model.term.TermVocabulary;
48
49 /**
50 * @author pplitzner
51 * @since May 3, 2016
52 */
53 @Component
54 public class BfnXmlTaxonNameExport extends BfnXmlExportBase {
55
56 private static final long serialVersionUID = -931703660108981011L;
57 private static final Logger logger = LogManager.getLogger();
58
59 public BfnXmlTaxonNameExport(){
60 super();
61 }
62
63 @Override
64 protected void doInvoke(BfnXmlExportState state){
65 startTransaction(true);
66
67 Document document = state.getConfig().getDocument();
68
69 //get all classifications
70 List<Classification> classifications = getClassificationService().list(Classification.class, null, null, null, null);
71 for (Classification classification : classifications) {
72 Element roteListeDaten = new Element(BfnXmlConstants.EL_ROTELISTEDATEN);
73 roteListeDaten.setAttribute(new Attribute(BfnXmlConstants.ATT_INHALT, classification.getTitleCache()));
74 document.getRootElement().addContent(roteListeDaten);
75
76 exportFeatures(roteListeDaten);
77
78 exportTaxonomy(classification, roteListeDaten, state);
79
80 }
81 }
82
83 private void exportTaxonomy(Classification classification, Element roteListeDaten, BfnXmlExportState state) {
84 Element taxonyme = new Element(BfnXmlConstants.EL_TAXONYME);
85 roteListeDaten.addContent(taxonyme);
86 List<TaxonNode> childNodes = classification.getChildNodes();
87 java.util.Collections.sort(childNodes, new TaxonComparator());
88 for (TaxonNode taxonNode : childNodes) {
89 exportTaxon(taxonNode.getTaxon(), taxonyme, state);
90 }
91 }
92
93 private void exportFactualData(Taxon taxon, Element parent) {
94 Element informationen = new Element(BfnXmlConstants.EL_INFORMATIONEN);
95 parent.addContent(informationen);
96 Element bezugsraum = new Element(BfnXmlConstants.EL_BEZUGSRAUM);
97 bezugsraum.setAttribute(new Attribute(BfnXmlConstants.ATT_NAME, BfnXmlConstants.BEZUGRAUM_BUND));
98 informationen.addContent(bezugsraum);
99
100 Set<TaxonDescription> descriptions = taxon.getDescriptions();
101 for (TaxonDescription taxonDescription : descriptions) {
102 //TODO: export only red list features ??
103 Set<DescriptionElementBase> descriptionElements = taxonDescription.getElements();
104 exportCategoricalData(BfnXmlConstants.VOC_RL_KAT, descriptionElements, taxon, parent);
105 exportCategoricalData(BfnXmlConstants.VOC_KAT, descriptionElements, taxon, parent);
106 exportCategoricalData(BfnXmlConstants.VOC_NEOBIOTA, descriptionElements, taxon, parent);
107 exportCategoricalData(BfnXmlConstants.VOC_AKTUELLE_BESTANDSSTITUATION, descriptionElements, taxon, parent);
108 exportCategoricalData(BfnXmlConstants.VOC_LANGFRISTIGER_BESTANDSTREND, descriptionElements, taxon, parent);
109 exportCategoricalData(BfnXmlConstants.VOC_KURZFRISTIGER_BESTANDSTREND, descriptionElements, taxon, parent);
110 exportCategoricalData(BfnXmlConstants.VOC_RISIKOFAKTOREN, descriptionElements, taxon, parent);
111 exportCategoricalData(BfnXmlConstants.VOC_SONDERFAELLE, descriptionElements, taxon, parent);
112 exportTextData(BfnXmlConstants.FEAT_LETZTER_NACHWEIS, descriptionElements, taxon, parent);
113 exportCategoricalData(BfnXmlConstants.VOC_VERANTWORTLICHKEIT, descriptionElements, taxon, parent);
114 exportTextData(BfnXmlConstants.FEAT_KOMMENTAR_TAXONOMIE, descriptionElements, taxon, parent);
115 exportTextData(BfnXmlConstants.FEAT_KOMMENTAR_GEFAEHRDUNG, descriptionElements, taxon, parent);
116 exportTextData(BfnXmlConstants.FEAT_WEITERE_KOMMENTARE, descriptionElements, taxon, parent);
117 exportCategoricalData(BfnXmlConstants.VOC_ALTE_RL_KAT, descriptionElements, taxon, parent);
118
119
120 // for (DescriptionElementBase descriptionElementBase : descriptionElements) {
121 // if(descriptionElementBase.isInstanceOf(CategoricalData.class)){
122 // CategoricalData categoricalData = HibernateProxyHelper.deproxy(descriptionElementBase, CategoricalData.class);
123 // Feature feature = categoricalData.getFeature();
124 // List<StateData> stateData = categoricalData.getStateData();
125 // if(stateData.size()!=1){
126 // logger.error("StateData does not have a size of 1 for feature "+feature.getLabel()+" in taxon "+taxon.getTitleCache());
127 // continue;
128 // }
129 // addIwert(bezugsraum, feature.getLabel(), stateData.iterator().next().getState().getLabel());
130 // }
131 // else if(descriptionElementBase.isInstanceOf(TextData.class)){
132 // TextData textData = HibernateProxyHelper.deproxy(descriptionElementBase, TextData.class);
133 // addIwert(bezugsraum, textData.getFeature().getLabel(), textData.getLanguageText(Language.GERMAN()).getText());
134 // }
135 // }
136 }
137 }
138
139 private void exportTextData(String featureLabel, Set<DescriptionElementBase> descriptionElements, Taxon taxon, Element parent){
140 for (DescriptionElementBase descriptionElementBase : descriptionElements) {
141 if(descriptionElementBase.getFeature().getLabel().equals(featureLabel)){
142 TextData textData = HibernateProxyHelper.deproxy(descriptionElementBase, TextData.class);
143 addIwert(parent, textData.getFeature().getLabel(), textData.getLanguageText(Language.GERMAN()).getText());
144 }
145 }
146 }
147
148 private void exportCategoricalData(String featureLabel, Set<DescriptionElementBase> descriptionElements, Taxon taxon, Element parent){
149 for (DescriptionElementBase descriptionElementBase : descriptionElements) {
150 if(descriptionElementBase.getFeature().getLabel().equals(featureLabel)){
151 CategoricalData categoricalData = HibernateProxyHelper.deproxy(descriptionElementBase, CategoricalData.class);
152 Feature feature = categoricalData.getFeature();
153 List<StateData> stateData = categoricalData.getStateData();
154 if(stateData.size()!=1){
155 logger.error("StateData does not have a size of 1 for feature "+feature.getLabel()+" in taxon "+taxon.getTitleCache());
156 continue;
157 }
158 addIwert(parent, feature.getLabel(), stateData.iterator().next().getState().getLabel());
159 }
160 }
161 }
162
163 private void exportFeatures(Element roteListeDaten) {
164 Element eigenschaften = new Element(BfnXmlConstants.EL_EIGENSCHAFTEN);
165 roteListeDaten.addContent(eigenschaften);
166 TermVocabulary<Feature> redListFeaturesVoc = getVocabularyService().load(BfnXmlTransformer.vocRLFeatures);
167 Set<Feature> terms = redListFeaturesVoc.getTerms();
168 for (Feature feature : terms) {
169 //export red list features
170 Element eigenschaft = new Element(BfnXmlConstants.EL_EIGENSCHAFT);
171 eigenschaft.setAttribute(new Attribute(BfnXmlConstants.ATT_STANDARDNAME, feature.getLabel()));
172 eigenschaften.addContent(eigenschaft);
173 if(feature.isSupportsCategoricalData()){
174 //export feature states
175 Element listenwerte = new Element(BfnXmlConstants.EL_LISTENWERTE);
176 eigenschaft.addContent(listenwerte);
177 Set<TermVocabulary<State>> supportedCategoricalEnumerations = feature.getSupportedCategoricalEnumerations();
178 for (TermVocabulary<State> termVocabulary : supportedCategoricalEnumerations) {
179 Set<State> featureStates = termVocabulary.getTerms();
180 // int reihenfolge = 1;
181 for (State featureState : featureStates) {
182 Element lwert = new Element(BfnXmlConstants.EL_LWERT);
183 // lwert.setAttribute(new Attribute(BfnXmlConstants.ATT_REIHENFOLGE, String.valueOf(reihenfolge)));
184 lwert.addContent(featureState.getLabel());
185 listenwerte.addContent(lwert);
186
187 // reihenfolge++;
188 }
189 }
190 }
191 }
192 }
193
194 private void exportTaxon(Taxon taxon, Element parent, BfnXmlExportState state) {
195 Element taxonym = new Element(BfnXmlConstants.EL_TAXONYM);
196 parent.addContent(taxonym);
197
198 //reihenfolge attribute
199 taxonym.setAttribute(BfnXmlConstants.ATT_REIHENFOLGE, getExtension(taxon, ExtensionType.ORDER()));
200 //getIdentifier(taxon, BfnXmlConstants.UUID_REIHENFOLGE_IDENTIFIER_TYPE));
201
202 //taxNr attribute
203 taxonym.setAttribute(BfnXmlConstants.ATT_TAXNR, getIdentifier(taxon, BfnXmlTransformer.UUID_TAX_NR_IDENTIFIER_TYPE));
204
205
206 exportWissName(taxon, taxonym);
207
208 //synonyms
209 Set<Synonym> synonyms = taxon.getSynonyms();
210 if(synonyms.size()>0){
211 Element synonymeElement = new Element(BfnXmlConstants.EL_SYNONYME);
212 taxonym.addContent(synonymeElement);
213 for (Synonym synonym : synonyms) {
214 Element synonymElement = new Element(BfnXmlConstants.EL_SYNONYM);
215 synonymeElement.addContent(synonymElement);
216 exportWissName(synonym, synonymElement);
217 }
218 }
219
220 //common name
221 exportCommonName(taxon, taxonym);
222
223 //factual data
224 exportFactualData(taxon, taxonym);
225
226
227 }
228
229 /**
230 * @param taxon
231 * @param order
232 * @return
233 */
234 private String getExtension(Taxon taxon, ExtensionType order) {
235 Set<String> set = taxon.getExtensions(order);
236 if (set.size() != 1){
237 logger.warn("Exactly 1 order extension should exist, but has " + set.size());
238 if (set.size() > 1){
239 return set.iterator().next();
240 }
241 return null;
242 }else{
243 return set.iterator().next();
244 }
245 }
246
247 private String getIdentifier(Taxon taxon, UUID identifierUuid) {
248 DefinedTerm identifierType = HibernateProxyHelper.deproxy(getTermService().load(identifierUuid), DefinedTerm.class);
249 Set<String> identfiers = taxon.getIdentifierStrings(identifierType);
250 if(identfiers.size()==1){
251 return identfiers.iterator().next();
252 }
253 else{
254 logger.error("Taxon "+taxon.getTitleCache()+" has none or multiple identifiers of type '"+identifierType.getLabel()+"'");
255 return null;
256 }
257 }
258
259 private void exportWissName(TaxonBase<?> taxon, Element parent) {
260 Element wissName = new Element(BfnXmlConstants.EL_WISSNAME);
261 parent.addContent(wissName);
262
263 INonViralName name = taxon.getName();
264 Rank rank = name.getRank();
265 //epithet 1,2,3
266 exportEpithet(taxon, wissName, name, rank);
267
268 //rank
269 addNanteil(wissName, BfnXmlConstants.BEREICH_RANG, BfnXmlTransformer.getRankCodeForRank(rank));
270
271
272 addNanteil(wissName, BfnXmlConstants.BEREICH_ORDNUNGSZAHL, null);//TODO
273 addNanteil(wissName, BfnXmlConstants.BEREICH_AUTONYM, null);//TODO
274 addNanteil(wissName, BfnXmlConstants.BEREICH_REICH, null);//TODO
275 addNanteil(wissName, BfnXmlConstants.BEREICH_BASTARD, null);//TODO
276
277 //authors
278 addNanteil(wissName, BfnXmlConstants.BEREICH_AUTOREN, name.getAuthorshipCache());
279
280 addNanteil(wissName, BfnXmlConstants.BEREICH_ZUSAETZE, null);//TODO
281 addNanteil(wissName, "SortWissName", null);//TODO
282 addNanteil(wissName, "SortArtEpi", null);//TODO
283 addNanteil(wissName, "SortDeutName", null);//TODO
284
285 //wissName
286 addNanteil(wissName, BfnXmlConstants.BEREICH_WISSNAME, name.getTitleCache());
287 }
288
289 private void exportEpithet(TaxonBase<?> taxon, Element wissName, INonViralName name, Rank rank) {
290 //eindeutiger Code
291 Set<IdentifiableSource> sources = taxon.getSources();
292 for (IdentifiableSource identifiableSource : sources) {
293 if(identifiableSource.getType().equals(OriginalSourceType.Import)
294 && identifiableSource.getIdNamespace().equals(BfnXmlConstants.EL_TAXONYM+":"
295 +BfnXmlConstants.EL_WISSNAME+":"+BfnXmlConstants.EL_NANTEIL+":"+BfnXmlConstants.BEREICH_EINDEUTIGER_CODE)){
296 addNanteil(wissName, BfnXmlConstants.BEREICH_EINDEUTIGER_CODE, identifiableSource.getIdInSource());
297 }
298 }
299
300 //epitheton1-2
301 addNanteil(wissName, BfnXmlConstants.BEREICH_EPITHETON1, name.getGenusOrUninomial());
302 if(rank.isLowerThan(RankClass.Genus)){
303 String epitheton2 = name.getInfraGenericEpithet();
304 if(epitheton2==null){
305 epitheton2 = name.getSpecificEpithet();
306 }
307 addNanteil(wissName, BfnXmlConstants.BEREICH_EPITHETON2, epitheton2);
308 }
309 //epitheton3
310 String epitheton3 = null;
311 if(rank.isLowerThan(RankClass.Species)){
312 epitheton3 = name.getInfraSpecificEpithet();
313 }
314 if(epitheton3==null){
315 epitheton3 = name.getSpecificEpithet();
316 }
317 addNanteil(wissName, BfnXmlConstants.BEREICH_EPITHETON3, epitheton3);
318
319 //epitheton4-5
320 addNanteil(wissName, BfnXmlConstants.BEREICH_EPITHETON4, null);
321 addNanteil(wissName, BfnXmlConstants.BEREICH_EPITHETON5, null);
322 }
323
324 private void exportCommonName(Taxon taxon, Element taxonym) {
325 Element deutscheNamen = new Element(BfnXmlConstants.EL_DEUTSCHENAMEN);
326 taxonym.addContent(deutscheNamen);
327
328 int sequenz = 1;
329 Set<TaxonDescription> descriptions = taxon.getDescriptions();
330 for (TaxonDescription taxonDescription : descriptions) {
331 Set<DescriptionElementBase> elements = taxonDescription.getElements();
332 for (DescriptionElementBase descriptionElementBase : elements) {
333 if(descriptionElementBase.isInstanceOf(CommonTaxonName.class)){
334 CommonTaxonName commonName = HibernateProxyHelper.deproxy(descriptionElementBase, CommonTaxonName.class);
335 if(commonName.getLanguage().equals(Language.GERMAN())){
336 Element dName = new Element(BfnXmlConstants.EL_DNAME);
337 Element trivialName = new Element(BfnXmlConstants.EL_TRIVIALNAME);
338 deutscheNamen.addContent(dName);
339 dName.addContent(trivialName);
340
341 dName.setAttribute(new Attribute(BfnXmlConstants.ATT_SEQUENZ, String.valueOf(sequenz)));
342 trivialName.addContent(commonName.getName());
343 }
344 }
345 }
346 sequenz++;
347 }
348 }
349
350 private void addNanteil(Element element, String bereich, String textContent) {
351 Element nanteil = new Element(BfnXmlConstants.EL_NANTEIL);
352 nanteil.setAttribute(new Attribute(BfnXmlConstants.ATT_BEREICH, bereich));
353 if(textContent!=null){
354 nanteil.addContent(textContent);
355 }
356 element.addContent(nanteil);
357 }
358
359 @Override
360 protected boolean doCheck(BfnXmlExportState state) {
361 return false;
362 }
363
364 @Override
365 protected boolean isIgnore(BfnXmlExportState state) {
366 return false;
367 }
368
369 private final class TaxonComparator implements Comparator<TaxonNode> {
370 @Override
371 public int compare(TaxonNode o1, TaxonNode o2) {
372 Taxon taxon1 = o1.getTaxon();
373 Taxon taxon2 = o2.getTaxon();
374
375 int reihenfolge1 = Integer.parseInt(getExtension(taxon1, ExtensionType.ORDER()));
376 int reihenfolge2 = Integer.parseInt(getExtension(taxon2, ExtensionType.ORDER()));
377
378 return reihenfolge1-reihenfolge2;
379 }
380 }
381
382 }