Project

General

Profile

Download (37.2 KB) Statistics
| Branch: | Revision:
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.bfnXml.in;
11

    
12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.LinkedHashMap;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.UUID;
18

    
19
import org.apache.commons.lang.StringUtils;
20
import org.apache.log4j.Logger;
21
import org.jdom.Element;
22
import org.jdom.Namespace;
23
import org.springframework.stereotype.Component;
24
import org.springframework.transaction.TransactionStatus;
25

    
26
import eu.etaxonomy.cdm.api.service.IClassificationService;
27
import eu.etaxonomy.cdm.api.service.ITaxonService;
28
import eu.etaxonomy.cdm.common.ResultWrapper;
29
import eu.etaxonomy.cdm.common.XmlHelp;
30
import eu.etaxonomy.cdm.io.redlist.bfnXml.BfnXmlConstants;
31
import eu.etaxonomy.cdm.model.common.CdmBase;
32
import eu.etaxonomy.cdm.model.common.ExtensionType;
33
import eu.etaxonomy.cdm.model.common.Language;
34
import eu.etaxonomy.cdm.model.description.CategoricalData;
35
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
36
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
37
import eu.etaxonomy.cdm.model.description.Distribution;
38
import eu.etaxonomy.cdm.model.description.Feature;
39
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
40
import eu.etaxonomy.cdm.model.description.State;
41
import eu.etaxonomy.cdm.model.description.TaxonDescription;
42
import eu.etaxonomy.cdm.model.description.TextData;
43
import eu.etaxonomy.cdm.model.location.NamedArea;
44
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
45
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
46
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
47
import eu.etaxonomy.cdm.model.name.Rank;
48
import eu.etaxonomy.cdm.model.name.TaxonName;
49
import eu.etaxonomy.cdm.model.reference.Reference;
50
import eu.etaxonomy.cdm.model.taxon.Classification;
51
import eu.etaxonomy.cdm.model.taxon.Synonym;
52
import eu.etaxonomy.cdm.model.taxon.SynonymType;
53
import eu.etaxonomy.cdm.model.taxon.Taxon;
54
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
55
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
56
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
57
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
58
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
59
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
60
import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
61
/**
62
 *
63
 * @author a.oppermann
64
 * @since 04.07.2013
65
 *
66
 */
67
//@Component("bfnXmlTaxonNameIO")
68
@Component
69
public class BfnXmlImportTaxonName extends BfnXmlImportBase {
70

    
71
    private static final long serialVersionUID = -6684136204048549833L;
72

    
73
    private static final Logger logger = Logger.getLogger(BfnXmlImportTaxonName.class);
74

    
75
	private static NomenclaturalCode nomenclaturalCode = null;
76
	private static int parsingProblemCounter = 0;
77
	private Map<Integer, Taxon> firstList;
78
	private Map<Integer, Taxon> secondList;
79

    
80
//    private ImportDeduplicationHelper<BfnXmlImportState> deduplicationHelper = (ImportDeduplicationHelper<BfnXmlImportState>)ImportDeduplicationHelper.NewInstance(this);
81

    
82
	public BfnXmlImportTaxonName(){
83
		super();
84
	}
85

    
86

    
87
	@Override
88
	@SuppressWarnings({"rawtypes" })
89
	public void doInvoke(BfnXmlImportState state){
90

    
91
		TransactionStatus tx = startTransaction();
92

    
93
		ITaxonService taxonService = getTaxonService();
94
		BfnXmlImportConfigurator config = state.getConfig();
95
		nomenclaturalCode = config.getNomenclaturalCode();
96
		Element elDataSet = getDataSetElement(config);
97
		//TODO set Namespace
98
		Namespace bfnNamespace = config.getBfnXmlNamespace();
99

    
100
		List<?> contentXML = elDataSet.getContent();
101
		Element currentElement = null;
102
		state.setFillSecondList(false);
103
		for(Object object:contentXML){
104

    
105
			if(object instanceof Element){
106
				currentElement = (Element)object;
107
				//import taxon lists
108
				if(currentElement.getName().equalsIgnoreCase(BfnXmlConstants.EL_ROTELISTEDATEN)){
109

    
110
					Map<UUID, TaxonBase> savedTaxonMap = extractTaxonNames(state, taxonService, config, currentElement, bfnNamespace);
111
					createOrUpdateClassification(state, taxonService, savedTaxonMap, currentElement);
112
				    state.setFillSecondList(true);
113

    
114
				}//import concept relations of taxon lists
115
				if(config.isHasSecondList()){
116
					if(currentElement.getName().equalsIgnoreCase(BfnXmlConstants.EL_KONZEPTBEZIEHUNGEN)){
117
						extractTaxonConceptRelationShips(bfnNamespace,currentElement);
118
					}
119
				}
120
			}
121
		}
122
        commitTransaction(tx);
123
		return;
124
	}
125

    
126
	/**
127
	 * This method will parse the XML concept relationships and tries to map them into cdm relationship types.
128
	 *
129
	 * @param bfnNamespace
130
	 * @param currentElement
131
	 */
132
	private void extractTaxonConceptRelationShips(Namespace bfnNamespace, Element currentElement) {
133
		String childName;
134
		String bfnElementName = BfnXmlConstants.EL_KONZEPTBEZIEHUNG;
135
		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
136
		@SuppressWarnings("unchecked")
137
        List<Element> elConceptList = currentElement.getChildren(bfnElementName, bfnNamespace);
138
		List<TaxonBase> updatedTaxonList = new ArrayList<>();
139
		for(Element element:elConceptList){
140

    
141
			childName = "TAXONYM1";
142
			Element elTaxon1 = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
143
			String taxNr1 = elTaxon1.getAttributeValue(BfnXmlConstants.ATT_TAXNR);
144
			int int1 = Integer.parseInt(taxNr1);
145
			Taxon taxon1 = firstList.get(int1);
146
			TaxonBase<?> taxonBase1 = getTaxonService().load(taxon1.getUuid());
147
			taxon1 = (Taxon)taxonBase1;
148

    
149
			childName = "TAXONYM2";
150
			Element elTaxon2 = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
151
			String taxNr2 = elTaxon2.getAttributeValue(BfnXmlConstants.ATT_TAXNR);
152
			int int2 = Integer.parseInt(taxNr2);
153
			Taxon taxon2 = secondList.get(int2);
154
			TaxonBase<?> taxonBase2 = getTaxonService().load(taxon2.getUuid());
155
			taxon2 = (Taxon) taxonBase2;
156

    
157
			childName = "STATUS";
158
			Element elConceptStatus = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
159
			String conceptStatusValue = elConceptStatus.getValue();
160
			conceptStatusValue = conceptStatusValue.replaceAll("\u00A0", "").trim();
161
			TaxonRelationshipType taxonRelationType = null;
162
			/**
163
			 * This if case only exists because it was decided not to have a included_in relationship type.
164
			 */
165
			if(conceptStatusValue.equalsIgnoreCase("<")){
166
				taxon2.addTaxonRelation(taxon1, TaxonRelationshipType.INCLUDES(), null, null);
167
			}else{
168
				taxonRelationType = BfnXmlTransformer.getTaxonRelationForConceptCode(conceptStatusValue);
169
				taxon1.addTaxonRelation(taxon2, taxonRelationType , null, null);
170
			}
171
			if(taxonRelationType != null && taxonRelationType.equals(TaxonRelationshipType.ALL_RELATIONSHIPS())){
172
				List<TaxonRelationship> relationsFromThisTaxon = (List<TaxonRelationship>) taxon1.getRelationsFromThisTaxon();
173
				TaxonRelationship taxonRelationship = relationsFromThisTaxon.get(0);
174
				taxonRelationship.setDoubtful(true);
175
			}
176
			updatedTaxonList.add(taxon2);
177
			updatedTaxonList.add(taxon1);
178
		}
179
		getTaxonService().saveOrUpdate(updatedTaxonList);
180
		logger.info("taxon relationships imported...");
181
	}
182

    
183
	/**
184
	 * This method stores the current imported maps in global variables to make
185
	 * them later available for matching the taxon relationships between these
186
	 * imported lists.
187
	 *
188
	 * @param state
189
	 * @param taxonMap
190
	 */
191
	private void prepareListforConceptImport(BfnXmlImportState state,Map<Integer, Taxon> taxonMap) {
192
		if(state.isFillSecondList()){
193
			secondList = taxonMap;
194
		}else{
195
			firstList = taxonMap;
196
		}
197
	}
198

    
199
	/**
200
	 *
201
	 * @param state
202
	 * @param taxonService
203
	 * @param config
204
	 * @param elDataSet
205
	 * @param bfnNamespace
206
	 * @return
207
	 */
208
	private Map<UUID, TaxonBase> extractTaxonNames(BfnXmlImportState state,
209
			ITaxonService taxonService, BfnXmlImportConfigurator config,
210
			Element elDataSet, Namespace bfnNamespace) {
211

    
212
	    logger.info("start make TaxonNames...");
213
		Map<Integer, Taxon> taxonMap = new LinkedHashMap<>();
214
		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
215
		String childName;
216
		boolean obligatory;
217

    
218
		childName = BfnXmlConstants.EL_TAXONYME;
219
		obligatory = false;
220
		Element elTaxonNames = XmlHelp.getSingleChildElement(success, elDataSet, childName, bfnNamespace, obligatory);
221

    
222
		String bfnElementName = BfnXmlConstants.EL_TAXONYM;
223
		@SuppressWarnings("unchecked")
224
        List<Element> elTaxonList = elTaxonNames.getChildren(bfnElementName, bfnNamespace);
225

    
226
		//for each taxonName
227
		for (Element elTaxon : elTaxonList){
228
			//create Taxon
229
			String taxonId = elTaxon.getAttributeValue(BfnXmlConstants.ATT_TAXNR);
230
			String reihenfolge = elTaxon.getAttributeValue(BfnXmlConstants.ATT_REIHENFOLGE);
231
			childName = BfnXmlConstants.EL_WISSNAME;
232
			Element elWissName = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
233
			String childElementName = BfnXmlConstants.EL_NANTEIL;
234
			Taxon taxon = createOrUpdateTaxon(success, taxonId, reihenfolge, config, bfnNamespace, elWissName, childElementName, state);
235

    
236
			//for each synonym
237
			childName = "SYNONYME";
238
			Element elSynonyms = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
239
			if(elSynonyms != null){
240
				childElementName = "SYNONYM";
241
				createOrUpdateSynonym(taxon, success, obligatory, bfnNamespace, childElementName,elSynonyms, taxonId, state);
242
			}
243

    
244
			//for vernacular name
245
			childName = BfnXmlConstants.EL_DEUTSCHENAMEN;
246
			Element elVernacularName = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
247
			if(elVernacularName != null){
248
				childElementName = BfnXmlConstants.EL_DNAME;
249
				createOrUpdateVernacularName(taxon, bfnNamespace, childElementName, elVernacularName, state);
250
			}
251

    
252
			//for each information concerning the taxon element
253
			//TODO Information block
254
			if(config.isDoInformationImport()){
255
				childName = BfnXmlConstants.EL_INFORMATIONEN;
256
				Element elInformations = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
257
				if(elInformations != null){
258
				    createOrUpdateInformation(taxon, bfnNamespace, elInformations, state);
259
				}
260
			}
261
			taxonMap.put(Integer.parseInt(taxonId), taxon);
262
		}
263

    
264
		//Quick'n'dirty to set concept relationships between two imported list
265
		prepareListforConceptImport(state, taxonMap);
266

    
267
		Map<UUID, TaxonBase> savedTaxonMap = taxonService.saveOrUpdate((Collection)taxonMap.values());
268

    
269
		logger.info("end makeTaxonNames ...");
270
		if (!success.getValue()){
271
			state.setUnsuccessfull();
272
		}
273
		return savedTaxonMap;
274
	}
275

    
276

    
277

    
278

    
279
	/**
280
	 * This will put the prior imported list into a classification
281
	 *
282
	 * @param state
283
	 * @param taxonService
284
	 * @param state
285
	 * @param savedTaxonMap
286
	 * @param currentElement
287
	 * @param state
288
	 * @return
289
	 */
290
	@SuppressWarnings("rawtypes")
291
	private boolean createOrUpdateClassification(BfnXmlImportState state, ITaxonService taxonService, Map<UUID, TaxonBase> savedTaxonMap, Element currentElement) {
292
		boolean isNewClassification = true;
293
		String name = state.getFirstClassificationName() + " " + currentElement.getAttributeValue("inhalt");
294
		Classification classification = Classification.NewInstance(name, state.getCurrentSecRef());
295
		String microRef = null; //state.getCurrentSecRef() == null ? null : state.getCurrentSecRef().getTitleCache();
296
		classification.addImportSource(null, null, state.getCompleteSourceRef(), microRef);
297

    
298
		for(TaxonBase tb:savedTaxonMap.values()){
299
			if(tb instanceof Taxon){
300
				TaxonBase tbase = CdmBase.deproxy(tb, TaxonBase.class);
301
				Taxon taxon = (Taxon)tbase;
302
				taxon = CdmBase.deproxy(taxon, Taxon.class);
303
				classification.addChildTaxon(taxon, null, null);
304
			}
305
		}
306
		IClassificationService classificationService = getClassificationService();
307
		classificationService.saveOrUpdate(classification);
308
		return isNewClassification;
309
	}
310

    
311

    
312
	/**
313
	 * Matches the XML attributes against CDM entities.<BR>
314
	 * Imports Scientific Name, Rank, etc. and creates a taxon.<br>
315
	 * <b>Existing taxon names won't be matched yet</b>
316
	 *
317
	 * @param success
318
	 * @param taxonId
319
	 * @param reihenfolge
320
	 * @param config
321
	 * @param bfnNamespace
322
	 * @param elTaxonName
323
	 * @param childElementName
324
	 * @param state
325
	 * @return
326
	 */
327

    
328
	@SuppressWarnings({ "unchecked" })
329
	private Taxon createOrUpdateTaxon(
330
			ResultWrapper<Boolean> success, String taxonId,
331
			String reihenfolge, BfnXmlImportConfigurator config, Namespace bfnNamespace,
332
			Element elTaxonName, String childElementName, BfnXmlImportState state) {
333

    
334
		List<Element> elWissNameList = elTaxonName.getChildren(childElementName, bfnNamespace);
335
		Rank rank = null;
336
		String strAuthor = null;
337
		String strSupplement = null;
338
		Taxon taxon = null;
339
		String uniqueID = null;
340
		String uriNameSpace = null;
341
//		Long uniqueID = null;
342
		for(Element elWissName:elWissNameList){
343

    
344
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Eindeutiger Code")){
345
				uriNameSpace = elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH);
346
				String textNormalize = elWissName.getTextNormalize();
347
				if(StringUtils.isBlank(textNormalize)){
348
					uniqueID = "";
349
				}else{
350
					uniqueID = textNormalize;
351
				}
352
			}
353
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Autoren")){
354
				strAuthor = elWissName.getTextNormalize();
355
			}
356
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Rang")){
357
				String strRank = elWissName.getTextNormalize();
358
				rank = makeRank(strRank);
359
			}
360
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Zusätze")){
361
				strSupplement = elWissName.getTextNormalize();
362
			}
363
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("wissName")){
364
				try{
365
					TaxonName name = parseNonviralNames(rank,strAuthor,strSupplement,elWissName);
366
					if(name.isProtectedTitleCache() == true){
367
						logger.warn("Taxon " + name.getTitleCache());
368
					}
369

    
370
					//TODO  extract to method?
371
					if(strSupplement != null){
372
						name.setAppendedPhrase(strSupplement);
373
					}
374
					if(strSupplement != null && strSupplement.equalsIgnoreCase("nom. illeg.")){
375
						name.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.ILLEGITIMATE()));
376
					}
377

    
378
	                //no deduplication wanted by BfN
379
//                  deduplicationHelper.replaceAuthorNamesAndNomRef(state, name);
380

    
381
					Reference secRef = state.isFillSecondList() ?
382
					        state.getSecondListSecRef():
383
					        state.getFirstListSecRef();
384
					state.setCurrentSecundumRef(secRef);
385
					taxon = Taxon.NewInstance(name, state.getCurrentSecRef());
386
					//set create and set path of nameSpace
387

    
388
					String namespace = getNamespace(uriNameSpace, elWissName);
389
					taxon.addImportSource(uniqueID, namespace, state.getCompleteSourceRef(), null);
390
                    name.addImportSource(uniqueID, namespace, state.getCompleteSourceRef(), null);
391

    
392
					taxon.addIdentifier(taxonId, getIdentiferType(state, BfnXmlTransformer.UUID_TAX_NR_IDENTIFIER_TYPE, "taxNr", "TaxNr attribute of Bfn Xml file", "taxNr", null));
393
					taxon.addExtension(reihenfolge, ExtensionType.ORDER());
394
					taxon.addIdentifier(reihenfolge, getIdentiferType(state, BfnXmlTransformer.UUID_REIHENFOLGE_IDENTIFIER_TYPE, "reihenfolge", "reihenfolge attribute of Bfn Xml file", "reihenfolge", null));
395
				} catch (UnknownCdmTypeException e) {
396
					success.setValue(false);
397
				}
398
			}
399
		}
400
		return taxon;
401
	}
402

    
403

    
404
    /**
405
     * @param uriNameSpace
406
     * @param elWissName
407
     * @return
408
     */
409
    protected String getNamespace(String uriNameSpace, Element elWissName) {
410
        Element parentElement = elWissName.getParentElement();
411
        Element grandParentElement = parentElement.getParentElement();
412
        String namespace = grandParentElement.getName() + ":" + parentElement.getName() + ":"+elWissName.getName() + ":" + uriNameSpace;
413
        return namespace;
414
    }
415

    
416
	/**
417
	 * Matches the XML attributes against CDM entities.<BR>
418
	 * Imports Scientific Name, Rank etc. and create a synonym.<br>
419
	 * <b>Existing synonym names won't be matched yet</b>
420
	 *
421
	 * @param taxon
422
	 * @param success
423
	 * @param obligatory
424
	 * @param bfnNamespace
425
	 * @param childElementName
426
	 * @param elSynonyms
427
	 * @param taxonId
428
	 * @param config
429
	 * @param state
430
	 */
431
	@SuppressWarnings({ "unchecked" })
432
	private void createOrUpdateSynonym(Taxon taxon, ResultWrapper<Boolean> success, boolean obligatory, Namespace bfnNamespace,
433
			     String childElementName, Element elSynonyms, String taxonId, BfnXmlImportState state) {
434

    
435
		String childName;
436
		List<Element> elSynonymList = elSynonyms.getChildren(childElementName, bfnNamespace);
437

    
438
		for(Element elSyn:elSynonymList){
439
			Rank rank = null;
440
			String strAuthor = null;
441
			String strSupplement = null;
442
			childName = BfnXmlConstants.EL_WISSNAME;
443
			Element elSynScientificName = XmlHelp.getSingleChildElement(success, elSyn, childName, bfnNamespace, obligatory);
444

    
445
			childElementName = BfnXmlConstants.EL_NANTEIL;
446
			List<Element> elSynDetails = elSynScientificName.getChildren(childElementName, bfnNamespace);
447

    
448
			for(Element elSynDetail:elSynDetails){
449
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH).equalsIgnoreCase("Rang")){
450
					String strRank = elSynDetail.getTextNormalize();
451
					rank = makeRank(strRank);
452
				}
453
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH).equalsIgnoreCase("Autoren")){
454
					strAuthor = elSynDetail.getTextNormalize();
455
				}
456
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Zusätze")){
457
					strSupplement = elSynDetail.getTextNormalize();
458
				}
459
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH).equalsIgnoreCase("wissName")){
460
					try{
461
						TaxonName name = parseNonviralNames(rank,strAuthor,strSupplement,elSynDetail);
462
						//BfN does not want any deduplication, to be on the save side that no
463
//				        deduplicationHelper.replaceAuthorNamesAndNomRef(state, name);
464

    
465
						//TODO find best matching Taxa
466
						Synonym synonym = Synonym.NewInstance(name, state.getCurrentSecRef());
467
						taxon.addSynonym(synonym, SynonymType.SYNONYM_OF());
468

    
469
					} catch (UnknownCdmTypeException e) {
470
						logger.warn("Name with id " + taxonId + " has unknown nomenclatural code.");
471
						success.setValue(false);
472
					}
473

    
474
				}
475

    
476
			}
477
		}
478
	}
479

    
480

    
481
	/**
482
	 *
483
	 * @param taxon
484
	 * @param bfnNamespace
485
	 * @param childElementName
486
	 * @param elVernacularName
487
	 * @param state
488
	 */
489
	private void createOrUpdateVernacularName(Taxon taxon,
490
			Namespace bfnNamespace, String childElementName,
491
			Element elVernacularName, BfnXmlImportState state) {
492

    
493
		@SuppressWarnings("unchecked")
494
        List<Element> elVernacularNameList = elVernacularName.getChildren(childElementName, bfnNamespace);
495

    
496
		TaxonDescription taxonDescription = getTaxonDescription(taxon, false, true);
497

    
498
		for(Element elVernacular : elVernacularNameList){
499
			Element child = elVernacular.getChild("TRIVIALNAME");
500
			if(child != null){
501
				makeCommonName(taxonDescription, child, state);
502
			}
503
		}
504

    
505
	}
506

    
507
	/**
508
	 *
509
	 * @param taxon
510
	 * @param bfnNamespace
511
	 * @param childElementName
512
	 * @param elInformations
513
	 * @param state
514
	 * @throws UnknownCdmTypeException
515
	 */
516

    
517
	@SuppressWarnings("unchecked")
518
	private void createOrUpdateInformation(Taxon taxon,
519
			Namespace bfnNamespace,
520
			Element elInformations,
521
			BfnXmlImportState state){
522

    
523
	    String childElementName = BfnXmlConstants.EL_BEZUGSRAUM;
524

    
525
		List<Element> elInformationList = elInformations.getChildren(childElementName, bfnNamespace);
526

    
527
		for(Element elInfo:elInformationList){
528
			//check if geographical scope is Bund and import only these information for now
529
			//TODO create several taxon descriptions for different geographical scope
530
			if(elInfo.getName().equalsIgnoreCase(BfnXmlConstants.EL_BEZUGSRAUM) && elInfo.getAttributeValue("name").equalsIgnoreCase("Bund")){
531
				childElementName = BfnXmlConstants.EL_IWERT;
532
				TaxonDescription taxonDescription = getTaxonDescription(taxon, false, true);
533
				try {
534
				    UUID  germanStateUUID = BfnXmlTransformer.getAreaUUID("Deutschland");
535
					NamedArea area = (NamedArea)getTermService().load(germanStateUUID);
536
					//FIXME GEOSCOPE_ID CANNOT BE NULL Exception
537
					if (area != null){
538
					    taxonDescription.addGeoScope(area);
539
					}else{
540
					    logger.warn("Did not find area 'Deutschland'");
541
					}
542
				} catch (UnknownCdmTypeException e) {
543
					// TODO Auto-generated catch block
544
					e.printStackTrace();
545
				}
546
				List<Element> elInfoDetailList = elInfo.getChildren(childElementName, bfnNamespace);
547

    
548
				for(Element elInfoDetail : elInfoDetailList){
549
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_RL_KAT)){
550
						makeFeatures(taxonDescription, elInfoDetail, state, false);
551
						createDistributionStatus(elInfoDetail, state, taxonDescription);
552
					}
553
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_KAT)){
554
						makeFeatures(taxonDescription, elInfoDetail, state, false);
555
					}
556
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_AKTUELLE_BESTANDSSTITUATION)){
557
						makeFeatures(taxonDescription, elInfoDetail, state, false);
558
					}
559
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_LANGFRISTIGER_BESTANDSTREND)){
560
						makeFeatures(taxonDescription, elInfoDetail, state, false);
561
					}
562
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_KURZFRISTIGER_BESTANDSTREND)){
563
						makeFeatures(taxonDescription, elInfoDetail, state, false);
564
					}
565
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_RISIKOFAKTOREN)){
566
						makeFeatures(taxonDescription, elInfoDetail, state, false);
567
					}
568
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_VERANTWORTLICHKEIT)){
569
						makeFeatures(taxonDescription, elInfoDetail, state, false);
570
					}
571
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_ALTE_RL_KAT)){
572
						makeFeatures(taxonDescription, elInfoDetail, state, false);
573
					}
574
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_NEOBIOTA)){
575
						makeFeatures(taxonDescription, elInfoDetail, state, false);
576
					}
577
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_EINDEUTIGER_CODE)){
578
						makeFeatures(taxonDescription, elInfoDetail, state, false);
579
					}
580
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.FEAT_KOMMENTAR_TAXONOMIE)){
581
						makeFeatures(taxonDescription, elInfoDetail, state, true);
582
					}
583
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.FEAT_KOMMENTAR_GEFAEHRDUNG)){
584
						makeFeatures(taxonDescription, elInfoDetail, state, true);
585
					}
586
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.VOC_SONDERFAELLE)){
587
						makeFeatures(taxonDescription, elInfoDetail, state, false);
588
					}
589
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.FEAT_LETZTER_NACHWEIS)){
590
						makeFeatures(taxonDescription, elInfoDetail, state, true);
591
					}
592
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase(BfnXmlConstants.FEAT_WEITERE_KOMMENTARE)){
593
						makeFeatures(taxonDescription, elInfoDetail, state, true);
594
					}
595
					//create german federal states distribution status
596
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BW")){
597
                        createDistributionStatus(elInfoDetail, state, taxonDescription);
598
                    }
599
					//create german federal states distribution status
600
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BY")){
601
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
602
					}
603
					//create german federal states distribution status
604
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BE")){
605
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
606
					}
607
					//create german federal states distribution status
608
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BB")){
609
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
610
					}
611
					//create german federal states distribution status
612
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("HB")){
613
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
614
					}
615
					//create german federal states distribution status
616
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("HH")){
617
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
618
					}
619
					//create german federal states distribution status
620
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("HE")){
621
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
622
					}
623
					//create german federal states distribution status
624
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("MV")){
625
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
626
					}
627
					//create german federal states distribution status
628
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("NI")){
629
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
630
					}
631
					//create german federal states distribution status
632
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("NW")){
633
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
634
					}
635
					//create german federal states distribution status
636
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("RP")){
637
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
638
					}
639
					//create german federal states distribution status
640
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("SL")){
641
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
642
					}
643
					//create german federal states distribution status
644
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("SN")){
645
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
646
					}
647
					//create german federal states distribution status
648
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("ST")){
649
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
650
					}
651
					//create german federal states distribution status
652
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("SH")){
653
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
654
					}
655
					//create german federal states distribution status
656
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("TH")){
657
					    createDistributionStatus(elInfoDetail, state, taxonDescription);
658
					}
659
				}
660
			}
661
		}
662
	}
663

    
664

    
665
    private void makeCommonName(TaxonDescription taxonDescription,
666
			Element child, BfnXmlImportState state) {
667
		String commonNameValue = child.getValue();
668
		NamedArea area = getTermService().getAreaByTdwgAbbreviation("GER");
669
		CommonTaxonName commonName = CommonTaxonName.NewInstance(commonNameValue, Language.GERMAN(), area);
670
		taxonDescription.addElement(commonName);
671
	}
672

    
673

    
674
	/**
675
	 *
676
	 * @param taxonDescription
677
	 * @param elInfoDetail
678
	 * @param state
679
	 * @param isTextData
680
	 */
681
	private void makeFeatures(
682
			TaxonDescription taxonDescription,
683
			Element elInfoDetail,
684
			BfnXmlImportState state,
685
			boolean isTextData) {
686

    
687
		String transformedRlKatValue = null;
688
		UUID featureUUID = null;
689
		UUID stateTermUUID = null;
690
		String strRlKatValue = elInfoDetail.getChild(BfnXmlConstants.EL_WERT).getValue();
691
		String strRlKat = elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME);
692
		boolean randomStateUUID = false;
693
		try {
694
			featureUUID = BfnXmlTransformer.getRedlistFeatureUUID(strRlKat);
695
			transformedRlKatValue = BfnXmlTransformer.redListString2RedListCode(strRlKatValue);
696
		} catch (UnknownCdmTypeException e) {
697
			transformedRlKatValue = strRlKatValue;
698
		}
699
		if (featureUUID == null){
700
		    logger.warn("featureUUID is null for " + strRlKat);
701
		}
702
		State rlState = null;
703
		//if is text data a state is not needed
704
		if(!isTextData){
705
			try {
706
				stateTermUUID = BfnXmlTransformer.getRedlistStateTermUUID(transformedRlKatValue, strRlKat);
707
			} catch (UnknownCdmTypeException e) {
708
				stateTermUUID = UUID.randomUUID();
709
				randomStateUUID = true;
710
			}
711
			if(randomStateUUID || stateTermUUID == BfnXmlTransformer.stateTermEmpty){
712
				if(stateTermUUID == BfnXmlTransformer.stateTermEmpty) {
713
                    transformedRlKatValue = "keine Angabe";
714
                }
715
				rlState = getStateTerm(state, stateTermUUID, transformedRlKatValue, transformedRlKatValue, transformedRlKatValue, null);
716
			}else{
717
				rlState = getStateTerm(state, stateTermUUID);
718
			}
719
		}
720

    
721
		if (featureUUID != null){
722
		    Feature redListFeature = getFeature(state, featureUUID);
723
		    if(isTextData){
724
		        TextData textData = TextData.NewInstance(redListFeature);
725
		        textData.putText(Language.GERMAN(), strRlKatValue);
726
		        DescriptionElementBase descriptionElement = textData;
727
		        taxonDescription.addElement(descriptionElement);
728
		    }else{
729
		        CategoricalData catData = CategoricalData.NewInstance(rlState, redListFeature);
730
		        DescriptionElementBase descriptionElement = catData;
731
		        taxonDescription.addElement(descriptionElement);
732
		    }
733
		}else{
734
		    logger.warn("Not descriptive data imported");
735
		}
736
	}
737

    
738
	/**
739
	 * Returns the rank represented by the rank element.<br>
740
	 * Returns <code>null</code> if the element is null.<br>
741
	 * Returns <code>null</code> if the code and the text are both either empty or do not exists.<br>
742
	 * Returns the rank represented by the code attribute, if the code attribute is not empty and could be resolved.<br>
743
	 * If the code could not be resolved it returns the rank represented most likely by the elements text.<br>
744
	 * Returns UNKNOWN_RANK if code attribute and element text could not be resolved.
745
	 * @param strRank bfn rank element
746
	 * @return
747
	 */
748
	protected static Rank makeRank(String strRank){
749
		Rank result;
750
 		if (StringUtils.isBlank(strRank)){
751
			return null;
752
		}
753
		Rank codeRank = BfnXmlTransformer.getRankForRankCode(strRank);
754
		if(codeRank==null){
755
		    codeRank = Rank.UNKNOWN_RANK();
756
		}
757
		//codeRank exists
758
		if ( (codeRank != null) && !codeRank.equals(Rank.UNKNOWN_RANK())){
759
			result = codeRank;
760
		}
761
		//codeRank does not exist
762
		else{
763
			result = codeRank;
764
			logger.warn("string rank ('"+strRank+"') used, because code rank does not exist or was not recognized: " + codeRank.getTitleCache()+" "+strRank);
765
		}
766
		return result;
767
	}
768

    
769
	/**
770
	 * @param rank
771
	 * @param strAuthor
772
	 * @param strSupplement
773
	 * @param elWissName
774
	 * @return
775
	 * @throws UnknownCdmTypeException
776
	 */
777
	private TaxonName parseNonviralNames(Rank rank, String strAuthor, String strSupplement, Element elWissName)
778
			throws UnknownCdmTypeException {
779
		TaxonName taxonNameBase = null;
780

    
781
		String strScientificName = elWissName.getTextNormalize();
782
		strScientificName = normalizeScientificName(strScientificName, strSupplement);
783
		NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
784
		TaxonName nonViralName = (TaxonName)parser.parseFullName(strScientificName, nomenclaturalCode, rank);
785
		if(nonViralName.hasProblem()){
786
			for(ParserProblem p: nonViralName.getParsingProblems()){
787
				logger.warn(++parsingProblemCounter + " " +nonViralName.getTitleCache() + " " + p.toString());
788
			}
789
		}
790
		//check for parsed rank
791
		Rank parsedRank = nonViralName.getRank();
792
		if(parsedRank != rank){
793
			nonViralName.setRank(rank);
794
		}
795
		//check for parsed author
796
		String parsedAuthor = nonViralName.getAuthorshipCache();
797
		strAuthor = StringUtils.trim(strAuthor);
798
		parsedAuthor = StringUtils.trim(parsedAuthor);
799
		if(parsedAuthor.equalsIgnoreCase(strAuthor)){
800
			logger.info("Taxon " + nonViralName.getTitleCache() +":"
801
					+"\t Author field: " + strAuthor +" and parsed AuthorshipCache: "+nonViralName.getAuthorshipCache());
802
		}
803
		taxonNameBase = nonViralName;
804
		return taxonNameBase;
805
	}
806

    
807

    
808
    /**
809
     * @param strSupplement
810
     * @param strScientificName
811
     * @return
812
     */
813
    protected String normalizeScientificName(String strScientificName, String strSupplement) {
814
        // trim strScienctificName because sometimes getTextNormalize() does not removes all the whitespaces
815
		strScientificName = StringUtils.trim(strScientificName);
816
		strScientificName = StringUtils.remove(strScientificName, "\u00a0");
817
		strScientificName = StringUtils.remove(strScientificName, "\uc281");
818

    
819
		if(StringUtils.isNotBlank(strSupplement)){
820
			strScientificName = StringUtils.remove(strScientificName, strSupplement);
821
		}
822
		//Eulenspinner/spanner have different taxon name syntax like "pupillata (Thunberg, 1788); Epirrhoe"
823
		if(strScientificName.contains(";")){
824
		    String[] splits = strScientificName.split(";");
825
		    if (splits.length != 2){
826
		        logger.warn("Unexpected length of semicolon scientific name: " + splits.length + "; " + strScientificName);
827
		    }
828
		    strScientificName = splits[1].trim() + " " + splits[0].trim();
829
		}
830

    
831
        return strScientificName;
832
    }
833

    
834
	/**
835
	 * This method will match the BFN XML status to a distribution status
836
	 * and map it to the german federal state area. The vocabulary needs to be
837
	 * created first by the Importer, in order to map the terms correctly. Have a look
838
	 * for further details at the file BfnXmlImportAdditionalTerms.
839
	 *
840
	 *
841
     * @param taxon, for saving the distribution and its status
842
     * @param elInfoDetail, keeps the details from the import, in this case the distribution detail
843
     * @param state, import state
844
     * @param germanState, the abbreviated label for the German state
845
     *
846
     */
847
    private void createDistributionStatus(Element elInfoDetail, BfnXmlImportState state,
848
            TaxonDescription taxonDescription){
849

    
850
        String strDistributionValue = elInfoDetail.getChild(BfnXmlConstants.EL_WERT).getValue();
851
        if (strDistributionValue.startsWith("#dtpl_RLKat")){
852
            try {
853
                strDistributionValue = BfnXmlTransformer.redListString2RedListCode(strDistributionValue);
854
            } catch (UnknownCdmTypeException e) {
855
                logger.warn("RL Kategorie " + strDistributionValue + " konnte nicht gematched werden ");
856
            }
857
        }
858
        String strArea = elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME);
859
        if (strArea.equals("RL Kat.")){
860
            strArea = "Deutschland";
861
        }
862
        //match DistributionValue
863
        UUID matchedDistributionUUID;
864
        try {
865
            matchedDistributionUUID = BfnXmlTransformer.matchDistributionValue(strDistributionValue);
866
        } catch (UnknownCdmTypeException e1) {
867
            logger.warn("could not match xml value "+ strDistributionValue +" to distribution status for "+strArea);
868
//            e1.printStackTrace();
869
            return;
870
        }
871
        if (matchedDistributionUUID == null){
872
            return;
873
        }
874
        PresenceAbsenceTerm status;
875
        DefinedTermBase<?> load = getTermService().load(matchedDistributionUUID);
876
        if(load.isInstanceOf(PresenceAbsenceTerm.class)) {
877
            status = CdmBase.deproxy(load, PresenceAbsenceTerm.class);
878
        }else{
879
            logger.warn(strDistributionValue + " is not PresenceAbsence Term " + load.getTitleCache() + " " + load.getTermType().toString());
880
            return;
881
        }
882
        //load vocabulary and german state
883
        UUID stateUUID = null;
884

    
885
        try {
886
            stateUUID = BfnXmlTransformer.getAreaUUID(strArea);
887
        } catch (UnknownCdmTypeException e1) {
888
            logger.warn("could not match state" + strArea + " to UUID");
889
            e1.printStackTrace();
890
            return;
891
        }
892
        NamedArea area = (NamedArea)getTermService().load(stateUUID);
893

    
894
//        try {
895
//            vocabularyUUID =  BfnXmlTransformer.getRedlistVocabularyUUID("Bundesländer");
896
//            vocabulary = getVocabularyService().load(vocabularyUUID);
897
//        } catch (UnknownCdmTypeException e) {
898
//            logger.warn("could not load vocabulary");
899
//            e.printStackTrace();
900
//            return;
901
//        }
902
//        NamedArea area = null;
903
//        for(Object term: vocabulary){
904
//            //TODO match german state
905
//            NamedArea narea = (NamedArea) term;
906
//            Set<Representation> representations = narea.getRepresentations();
907
//            for(Representation r:representations){
908
//                if(r.getAbbreviatedLabel().equalsIgnoreCase(strGermanState)){
909
//                    area = narea;
910
//                }
911
//            }
912
//
913
//        }
914
        //add to taxon description
915
        DescriptionElementBase descriptionElement = Distribution.NewInstance(area, status);
916
        taxonDescription.addElement(descriptionElement);
917
    }
918

    
919

    
920
    @Override
921
    public boolean doCheck(BfnXmlImportState state){
922
        boolean result = true;
923
        return result;
924
    }
925

    
926
	@Override
927
	protected boolean isIgnore(BfnXmlImportState state){
928
		return ! state.getConfig().isDoTaxonNames();
929
	}
930
}
(8-8/9)