Project

General

Profile

Download (36.7 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.DefinedTermBase;
33
import eu.etaxonomy.cdm.model.common.Language;
34
import eu.etaxonomy.cdm.model.common.TermVocabulary;
35
import eu.etaxonomy.cdm.model.description.CategoricalData;
36
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
37
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
38
import eu.etaxonomy.cdm.model.description.Distribution;
39
import eu.etaxonomy.cdm.model.description.Feature;
40
import eu.etaxonomy.cdm.model.description.PresenceAbsenceTerm;
41
import eu.etaxonomy.cdm.model.description.State;
42
import eu.etaxonomy.cdm.model.description.TaxonDescription;
43
import eu.etaxonomy.cdm.model.description.TextData;
44
import eu.etaxonomy.cdm.model.location.NamedArea;
45
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
46
import eu.etaxonomy.cdm.model.name.NomenclaturalStatus;
47
import eu.etaxonomy.cdm.model.name.NomenclaturalStatusType;
48
import eu.etaxonomy.cdm.model.name.NonViralName;
49
import eu.etaxonomy.cdm.model.name.Rank;
50
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
51
import eu.etaxonomy.cdm.model.reference.Reference;
52
import eu.etaxonomy.cdm.model.taxon.Classification;
53
import eu.etaxonomy.cdm.model.taxon.Synonym;
54
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
55
import eu.etaxonomy.cdm.model.taxon.Taxon;
56
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
57
import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
58
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
59
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
60
import eu.etaxonomy.cdm.strategy.parser.NonViralNameParserImpl;
61
import eu.etaxonomy.cdm.strategy.parser.ParserProblem;
62
/**
63
 *
64
 * @author a.oppermann
65
 * @date 04.07.2013
66
 *
67
 */
68
//@Component("bfnXmlTaxonNameIO")
69
@Component
70
public class BfnXmlImportTaxonName extends BfnXmlImportBase {
71

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

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

    
79

    
80
	public BfnXmlImportTaxonName(){
81
		super();
82
	}
83

    
84

    
85
	@Override
86
	@SuppressWarnings({"rawtypes" })
87
	public void doInvoke(BfnXmlImportState state){
88
		ITaxonService taxonService = getTaxonService();
89

    
90
		BfnXmlImportConfigurator config = state.getConfig();
91
		nomenclaturalCode = config.getNomenclaturalCode();
92
		Element elDataSet = getDataSetElement(config);
93
		//TODO set Namespace
94
		Namespace bfnNamespace = config.getBfnXmlNamespace();
95

    
96
		List<?> contentXML = elDataSet.getContent();
97
		Element currentElement = null;
98
		for(Object object:contentXML){
99

    
100
			if(object instanceof Element){
101
				currentElement = (Element)object;
102
				//import taxon lists
103
				if(currentElement.getName().equalsIgnoreCase(BfnXmlConstants.EL_ROTELISTEDATEN)){
104
					TransactionStatus tx = startTransaction();
105
					Map<UUID, TaxonBase> savedTaxonMap = extractTaxonNames(state, taxonService, config, currentElement, bfnNamespace);
106
					createOrUpdateClassification(config, taxonService, savedTaxonMap, currentElement, state);
107
					commitTransaction(tx);
108
				}//import concept relations of taxon lists
109
				if(config.isHasSecondList()){
110
					if(currentElement.getName().equalsIgnoreCase(BfnXmlConstants.EL_KONZEPTBEZIEHUNGEN)){
111
						TransactionStatus tx = startTransaction();
112
						extractTaxonConceptRelationShips(bfnNamespace,currentElement);
113
						commitTransaction(tx);
114
					}
115
				}
116
			}
117
		}
118
		return;
119
	}
120

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

    
135
			childName = "TAXONYM1";
136
			Element elTaxon1 = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
137
			String taxNr1 = elTaxon1.getAttributeValue(BfnXmlConstants.ATT_TAXNR);
138
			int int1 = Integer.parseInt(taxNr1);
139
			Taxon taxon1 = firstList.get(int1);
140
			TaxonBase<?> taxonBase1 = getTaxonService().load(taxon1.getUuid());
141
			taxon1 = (Taxon)taxonBase1;
142

    
143
			childName = "TAXONYM2";
144
			Element elTaxon2 = XmlHelp.getSingleChildElement(success, element, childName, bfnNamespace, false);
145
			String taxNr2 = elTaxon2.getAttributeValue(BfnXmlConstants.ATT_TAXNR);
146
			int int2 = Integer.parseInt(taxNr2);
147
			Taxon taxon2 = secondList.get(int2);
148
			TaxonBase<?> taxonBase2 = getTaxonService().load(taxon2.getUuid());
149
			taxon2 = (Taxon) taxonBase2;
150

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

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

    
197
	/**
198
	 *
199
	 * @param state
200
	 * @param taxonService
201
	 * @param config
202
	 * @param elDataSet
203
	 * @param bfnNamespace
204
	 * @return
205
	 */
206
	private Map<UUID, TaxonBase> extractTaxonNames(BfnXmlImportState state,
207
			ITaxonService taxonService, BfnXmlImportConfigurator config,
208
			Element elDataSet, Namespace bfnNamespace) {
209
		logger.info("start make TaxonNames...");
210
		Map<Integer, Taxon> taxonMap = new LinkedHashMap<Integer, Taxon>();
211
		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
212
		String childName;
213
		boolean obligatory;
214
		String idNamespace = "TaxonName";
215

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

    
220
		String bfnElementName = BfnXmlConstants.EL_TAXONYM;
221
		List<Element> elTaxonList = elTaxonNames.getChildren(bfnElementName, bfnNamespace);
222

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

    
232
			//for each synonym
233
			childName = "SYNONYME";
234
			Element elSynonyms = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
235
			if(elSynonyms != null){
236
				childElementName = "SYNONYM";
237
				createOrUpdateSynonym(taxon, success, obligatory, bfnNamespace, childElementName,elSynonyms, taxonId, state);
238
			}
239
			//for vernacular name
240
			childName = BfnXmlConstants.EL_DEUTSCHENAMEN;
241
			Element elVernacularName = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
242
			if(elVernacularName != null){
243
				childElementName = BfnXmlConstants.EL_DNAME;
244
				createOrUpdateVernacularName(taxon, bfnNamespace, childElementName, elVernacularName, state);
245
			}
246
			//for each information concerning the taxon element
247
			//TODO Information block
248
			if(config.isDoInformationImport()){
249
				childName = BfnXmlConstants.EL_INFORMATIONEN;
250
				Element elInformations = XmlHelp.getSingleChildElement(success, elTaxon, childName, bfnNamespace, obligatory);
251
				if(elInformations != null){
252
					childElementName = BfnXmlConstants.EL_BEZUGSRAUM;
253
					createOrUpdateInformation(taxon, bfnNamespace, childElementName,elInformations, state);
254
				}
255
			}
256
			taxonMap.put(Integer.parseInt(taxonId), taxon);
257
		}
258

    
259
		//Quick'n'dirty to set concept relationships between two imported list
260
		prepareListforConceptImport(config, taxonMap);
261

    
262
		Map<UUID, TaxonBase> savedTaxonMap = taxonService.saveOrUpdate((Collection)taxonMap.values());
263
		//FIXME: after first list don't import metadata yet
264
		//TODO: import information for second taxon list.
265
		config.setDoInformationImport(false);
266
		logger.info("end makeTaxonNames ...");
267
		if (!success.getValue()){
268
			state.setUnsuccessfull();
269
		}
270
		return savedTaxonMap;
271
	}
272

    
273

    
274

    
275

    
276
	/**
277
	 * This will put the prior imported list into a classification
278
	 *
279
	 * @param config
280
	 * @param taxonService
281
	 * @param config
282
	 * @param savedTaxonMap
283
	 * @param currentElement
284
	 * @param state
285
	 * @return
286
	 */
287
	@SuppressWarnings("rawtypes")
288
	private boolean createOrUpdateClassification(BfnXmlImportConfigurator config, ITaxonService taxonService, Map<UUID, TaxonBase> savedTaxonMap, Element currentElement, BfnXmlImportState state) {
289
		boolean isNewClassification = true;
290
		String classificationName = state.getFirstClassificationName();
291
		if(config.isFillSecondList()){
292
			classificationName = state.getSecondClassificationName();
293
		}
294
//		if(classificationName == null){
295
//			classificationName = config.getClassificationName();
296
//		}
297
		//TODO make classification name dynamically depending on its value in the XML.
298
		Classification classification = Classification.NewInstance(classificationName+" "+currentElement.getAttributeValue("inhalt"), state.getCompleteSourceRef());
299
		//TODO do we really want toString() or titleCache here?
300
		String microRef = state.getCurrentMicroRef() == null ? null : state.getCurrentMicroRef().toString();
301
		classification.addImportSource(Integer.toString(classification.getId()), classification.getTitleCache(), state.getCompleteSourceRef(), microRef);
302
//		List<Classification> classificationList = getClassificationService().list(Classification.class, null, null, null, VOC_CLASSIFICATION_INIT_STRATEGY);
303
//		for(Classification c : classificationList){
304
//			if(c.getTitleCache().equalsIgnoreCase(classification.getTitleCache())){
305
//				classification = c;
306
//				isNewClassification = false;
307
//			}
308
//		}
309

    
310
//		ArrayList<TaxonBase> taxonBaseList = (ArrayList<TaxonBase>) taxonService.list(TaxonBase.class, null, null, null, VOC_CLASSIFICATION_INIT_STRATEGY);
311
		for(TaxonBase tb:savedTaxonMap.values()){
312
			if(tb instanceof Taxon){
313
				TaxonBase tbase = CdmBase.deproxy(tb, TaxonBase.class);
314
				Taxon taxon = (Taxon)tbase;
315
				taxon = CdmBase.deproxy(taxon, Taxon.class);
316
				classification.addChildTaxon(taxon, null, null);
317
			}
318
		}
319
		IClassificationService classificationService = getClassificationService();
320
		classificationService.saveOrUpdate(classification);
321
		//set boolean for reference and internal mapping of concept relations
322
		if(config.isHasSecondList()){
323
			config.setFillSecondList(true);
324
		}
325
		return isNewClassification;
326
	}
327

    
328

    
329

    
330
	/**
331
	 * Matches the XML attributes against CDM entities.<BR>
332
	 * Imports Scientific Name, Rank, etc. and creates a taxon.<br>
333
	 * <b>Existing taxon names won't be matched yet</b>
334
	 *
335
	 * @param success
336
	 * @param taxonId
337
	 * @param config
338
	 * @param bfnNamespace
339
	 * @param elTaxonName
340
	 * @param childElementName
341
	 * @param state
342
	 * @return
343
	 */
344

    
345
	@SuppressWarnings({ "unchecked" })
346
	private Taxon createOrUpdateTaxon(
347
			ResultWrapper<Boolean> success, String taxonId,
348
			BfnXmlImportConfigurator config, Namespace bfnNamespace,
349
			Element elTaxonName, String childElementName, BfnXmlImportState state) {
350

    
351
		List<Element> elWissNameList = elTaxonName.getChildren(childElementName, bfnNamespace);
352
		Rank rank = null;
353
		String strAuthor = null;
354
		String strSupplement = null;
355
		Taxon taxon = null;
356
		String uniqueID = null;
357
		String uriNameSpace = null;
358
//		Long uniqueID = null;
359
		for(Element elWissName:elWissNameList){
360

    
361
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Eindeutiger Code")){
362
				uriNameSpace = elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH);
363
				String textNormalize = elWissName.getTextNormalize();
364
				if(StringUtils.isBlank(textNormalize)){
365
					uniqueID = "";
366
				}else{
367
					uniqueID = textNormalize;
368
				}
369
			}
370
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Autoren")){
371
				strAuthor = elWissName.getTextNormalize();
372
			}
373
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Rang")){
374
				String strRank = elWissName.getTextNormalize();
375
				rank = makeRank(strRank);
376
			}
377
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Zusätze")){
378
				strSupplement = elWissName.getTextNormalize();
379
			}
380
			if(elWissName.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("wissName")){
381
				try{
382
					TaxonNameBase<?, ?> nameBase = parseNonviralNames(rank,strAuthor,strSupplement,elWissName);
383
					if(nameBase.isProtectedTitleCache() == true){
384
						logger.warn("Taxon " + nameBase.getTitleCache());
385
					}
386

    
387
					//TODO  extract to method?
388
					if(strSupplement != null){
389
						nameBase.setAppendedPhrase(strSupplement);
390
					}
391
					if(strSupplement != null && strSupplement.equalsIgnoreCase("nom. illeg.")){
392
						nameBase.addStatus(NomenclaturalStatus.NewInstance(NomenclaturalStatusType.ILLEGITIMATE()));
393
					}
394
					/**
395
					 *  BFN does not want any name matching yet
396
					 */
397
//					TaxonBase<?> taxonBase = null;
398
//					//TODO find best matching Taxa
399
//					Pager<TaxonNameBase> names = getNameService().findByTitle(null, nameBase.getTitleCache(), null, null, null, null, null, null);
400
//					//TODO  correct handling for pager
401
//					List<TaxonNameBase> nameList = names.getRecords();
402
//					if (nameList.isEmpty()){
403
//						taxonBase = Taxon.NewInstance(nameBase, config.getSourceReference());
404
//					}else{
405
//						taxonBase = Taxon.NewInstance(nameList.get(0), config.getSourceReference());
406
//						if (nameList.size()>1){
407
//							logger.warn("More than 1 matching taxon name found for " + nameBase.getTitleCache());
408
//						}
409
//					}
410

    
411
					Reference<?> microRef = config.isFillSecondList() ?
412
					        state.getSecondListSecRef():
413
					        state.getFirstListSecRef();
414
					state.setCurrentMicroRef(microRef);
415
					taxon = Taxon.NewInstance(nameBase, state.getCurrentMicroRef());
416
					//set create and set path of nameSpace
417
					Element parentElement = elWissName.getParentElement();
418
					Element grandParentElement = parentElement.getParentElement();
419
					String namespace = grandParentElement.getName() + ":" + parentElement.getName() + ":"+elWissName.getName() + ":" + uriNameSpace;
420
					String microRefStr = microRef == null ? null : microRef.getTitle();
421
					taxon.addImportSource(uniqueID, namespace, state.getCompleteSourceRef(), microRefStr);
422

    
423
					taxon.addIdentifier(taxonId, getIdentiferType(state, BfnXmlConstants.TAX_NR_IDENTIFIER, "taxNr", "TaxNr attribute of Bfn Xml file", "taxNr", null));
424
				} catch (UnknownCdmTypeException e) {
425
					success.setValue(false);
426
				}
427
			}
428
		}
429
		return taxon;
430
	}
431

    
432
	/**
433
	 * Matches the XML attributes against CDM entities.<BR>
434
	 * Imports Scientific Name, Rank etc. and create a synonym.<br>
435
	 * <b>Existing synonym names won't be matched yet</b>
436
	 *
437
	 * @param taxon
438
	 * @param success
439
	 * @param obligatory
440
	 * @param bfnNamespace
441
	 * @param childElementName
442
	 * @param elSynonyms
443
	 * @param taxonId
444
	 * @param config
445
	 * @param state
446
	 */
447

    
448
	@SuppressWarnings({ "unchecked" })
449
	private void createOrUpdateSynonym(Taxon taxon, ResultWrapper<Boolean> success, boolean obligatory, Namespace bfnNamespace,
450
			     String childElementName, Element elSynonyms, String taxonId, BfnXmlImportState state) {
451

    
452
		String childName;
453
		List<Element> elSynonymList = elSynonyms.getChildren(childElementName, bfnNamespace);
454

    
455
		for(Element elSyn:elSynonymList){
456
			Rank rank = null;
457
			String strAuthor = null;
458
			String strSupplement = null;
459
			childName = BfnXmlConstants.EL_WISSNAME;
460
			Element elSynScientificName = XmlHelp.getSingleChildElement(success, elSyn, childName, bfnNamespace, obligatory);
461

    
462
			childElementName = BfnXmlConstants.EL_NANTEIL;
463
			List<Element> elSynDetails = elSynScientificName.getChildren(childElementName, bfnNamespace);
464

    
465
			for(Element elSynDetail:elSynDetails){
466
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH).equalsIgnoreCase("Rang")){
467
					String strRank = elSynDetail.getTextNormalize();
468
					rank = makeRank(strRank);
469
				}
470
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH).equalsIgnoreCase("Autoren")){
471
					strAuthor = elSynDetail.getTextNormalize();
472
				}
473
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH, bfnNamespace).equalsIgnoreCase("Zusätze")){
474
					strSupplement = elSynDetail.getTextNormalize();
475
				}
476
				if(elSynDetail.getAttributeValue(BfnXmlConstants.ATT_BEREICH).equalsIgnoreCase("wissName")){
477
					try{
478
						TaxonNameBase<?, ?> nameBase = parseNonviralNames(rank,strAuthor,strSupplement,elSynDetail);
479

    
480
						//TODO find best matching Taxa
481
						Synonym synonym = Synonym.NewInstance(nameBase, state.getCurrentMicroRef());
482
						taxon.addSynonym(synonym, SynonymRelationshipType.SYNONYM_OF());
483

    
484
					} catch (UnknownCdmTypeException e) {
485
						logger.warn("Name with id " + taxonId + " has unknown nomenclatural code.");
486
						success.setValue(false);
487
					}
488

    
489
				}
490

    
491
			}
492
		}
493
	}
494

    
495

    
496
	/**
497
	 *
498
	 * @param taxon
499
	 * @param bfnNamespace
500
	 * @param childElementName
501
	 * @param elVernacularName
502
	 * @param state
503
	 */
504
	private void createOrUpdateVernacularName(Taxon taxon,
505
			Namespace bfnNamespace, String childElementName,
506
			Element elVernacularName, BfnXmlImportState state) {
507

    
508
		List<Element> elVernacularNameList = elVernacularName.getChildren(childElementName, bfnNamespace);
509

    
510
		TaxonDescription taxonDescription = getTaxonDescription(taxon, false, true);
511

    
512
		for(Element elVernacular : elVernacularNameList){
513
			Element child = elVernacular.getChild("TRIVIALNAME");
514
			if(child != null){
515
				makeCommonName(taxonDescription, child, state);
516
			}
517
		}
518

    
519
	}
520

    
521
	/**
522
	 *
523
	 * @param taxon
524
	 * @param bfnNamespace
525
	 * @param childElementName
526
	 * @param elInformations
527
	 * @param state
528
	 * @throws UnknownCdmTypeException
529
	 */
530

    
531
	@SuppressWarnings("unchecked")
532
	private void createOrUpdateInformation(Taxon taxon,
533
			Namespace bfnNamespace, String childElementName,
534
			Element elInformations,
535
			BfnXmlImportState state){
536

    
537
		List<Element> elInformationList = elInformations.getChildren(childElementName, bfnNamespace);
538

    
539
		for(Element elInfo:elInformationList){
540
			//check if geographical scope is Bund and import only these information for now
541
			//TODO create several taxon descriptions for different geographical scope
542
			if(elInfo.getName().equalsIgnoreCase(BfnXmlConstants.EL_BEZUGSRAUM) && elInfo.getAttributeValue("name").equalsIgnoreCase("Bund")){
543
				childElementName = BfnXmlConstants.EL_IWERT;
544
				TaxonDescription taxonDescription = getTaxonDescription(taxon, false, true);
545
				UUID germanStateUUID;
546
				try {
547
					germanStateUUID = BfnXmlTransformer.getGermanStateUUID("Deutschland");
548
					NamedArea area = (NamedArea)getTermService().load(germanStateUUID);
549
					//FIXME GEOSCOPE_ID CANNOT BE NULL Exception
550
//					taxonDescription.addGeoScope(area);
551
				} catch (UnknownCdmTypeException e) {
552
					// TODO Auto-generated catch block
553
					e.printStackTrace();
554
				}
555
				List<Element> elInfoDetailList = elInfo.getChildren(childElementName, bfnNamespace);
556

    
557
				for(Element elInfoDetail : elInfoDetailList){
558
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("RL Kat.")){
559
						makeFeatures(taxonDescription, elInfoDetail, state, false);
560
					}
561
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Kat. +/-")){
562
						makeFeatures(taxonDescription, elInfoDetail, state, false);
563
					}
564
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("aktuelle Bestandsstituation")){
565
						makeFeatures(taxonDescription, elInfoDetail, state, false);
566
					}
567
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("langfristiger Bestandstrend")){
568
						makeFeatures(taxonDescription, elInfoDetail, state, false);
569
					}
570
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("kurzfristiger Bestandstrend")){
571
						makeFeatures(taxonDescription, elInfoDetail, state, false);
572
					}
573
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Risikofaktoren")){
574
						makeFeatures(taxonDescription, elInfoDetail, state, false);
575
					}
576
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Verantwortlichkeit")){
577
						makeFeatures(taxonDescription, elInfoDetail, state, false);
578
					}
579
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("alte RL- Kat.")){
580
						makeFeatures(taxonDescription, elInfoDetail, state, false);
581
					}
582
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Neobiota")){
583
						makeFeatures(taxonDescription, elInfoDetail, state, false);
584
					}
585
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Eindeutiger Code")){
586
						makeFeatures(taxonDescription, elInfoDetail, state, false);
587
					}
588
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Kommentar zur Taxonomie")){
589
						makeFeatures(taxonDescription, elInfoDetail, state, true);
590
					}
591
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Kommentar zur Gefährdung")){
592
						makeFeatures(taxonDescription, elInfoDetail, state, true);
593
					}
594
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Sonderfälle")){
595
						makeFeatures(taxonDescription, elInfoDetail, state, false);
596
					}
597
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Letzter Nachweis")){
598
						makeFeatures(taxonDescription, elInfoDetail, state, true);
599
					}
600
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("Weitere Kommentare")){
601
						makeFeatures(taxonDescription, elInfoDetail, state, true);
602
					}
603
					//create german federal states distribution status
604
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BW")){
605
                        createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
606
                    }
607
					//create german federal states distribution status
608
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BY")){
609
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
610
					}
611
					//create german federal states distribution status
612
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BE")){
613
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
614
					}
615
					//create german federal states distribution status
616
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("BB")){
617
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
618
					}
619
					//create german federal states distribution status
620
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("HB")){
621
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
622
					}
623
					//create german federal states distribution status
624
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("HH")){
625
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
626
					}
627
					//create german federal states distribution status
628
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("HE")){
629
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
630
					}
631
					//create german federal states distribution status
632
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("MV")){
633
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
634
					}
635
					//create german federal states distribution status
636
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("NI")){
637
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
638
					}
639
					//create german federal states distribution status
640
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("NW")){
641
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
642
					}
643
					//create german federal states distribution status
644
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("RP")){
645
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
646
					}
647
					//create german federal states distribution status
648
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("SL")){
649
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
650
					}
651
					//create german federal states distribution status
652
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("SN")){
653
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
654
					}
655
					//create german federal states distribution status
656
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("ST")){
657
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
658
					}
659
					//create german federal states distribution status
660
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("SH")){
661
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
662
					}
663
					//create german federal states distribution status
664
					if(elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME).equalsIgnoreCase("TH")){
665
					    createGermanDistributionStatus(taxon, elInfoDetail, state, taxonDescription);
666
					}
667
				}
668
			}
669
		}
670
	}
671

    
672

    
673
    private void makeCommonName(TaxonDescription taxonDescription,
674
			Element child, BfnXmlImportState state) {
675
		String commonNameValue = child.getValue();
676
		NamedArea area = getTermService().getAreaByTdwgAbbreviation("GER");
677
		CommonTaxonName commonName = CommonTaxonName.NewInstance(commonNameValue, Language.GERMAN(), area);
678
		taxonDescription.addElement(commonName);
679
	}
680

    
681

    
682
	/**
683
	 *
684
	 * @param taxonDescription
685
	 * @param elInfoDetail
686
	 * @param state
687
	 * @param isTextData
688
	 */
689
	private void makeFeatures(
690
			TaxonDescription taxonDescription,
691
			Element elInfoDetail,
692
			BfnXmlImportState state,
693
			boolean isTextData) {
694

    
695
		String transformedRlKatValue = null;
696
		UUID featureUUID = null;
697
		UUID stateTermUUID = null;
698
		String strRlKatValue = elInfoDetail.getChild(BfnXmlConstants.EL_WERT).getValue();
699
		String strRlKat = elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME);
700
		boolean randomStateUUID = false;
701
		try {
702
			featureUUID = BfnXmlTransformer.getRedlistFeatureUUID(strRlKat);
703
			transformedRlKatValue = BfnXmlTransformer.redListString2RedListCode(strRlKatValue);
704
		} catch (UnknownCdmTypeException e) {
705
			transformedRlKatValue = strRlKatValue;
706
		}
707
		Feature redListFeature = getFeature(state, featureUUID);
708
		State rlState = null;
709
		//if is text data a state is not needed
710
		if(!isTextData){
711
			try {
712
				stateTermUUID = BfnXmlTransformer.getRedlistStateTermUUID(transformedRlKatValue, strRlKat);
713
			} catch (UnknownCdmTypeException e) {
714
				stateTermUUID = UUID.randomUUID();
715
				randomStateUUID = true;
716
			}
717
			if(randomStateUUID || stateTermUUID == BfnXmlConstants.stateTermEmpty){
718
				if(stateTermUUID == BfnXmlConstants.stateTermEmpty) {
719
                    transformedRlKatValue = "keine Angabe";
720
                }
721
				rlState = getStateTerm(state, stateTermUUID, transformedRlKatValue, transformedRlKatValue, transformedRlKatValue, null);
722
			}else{
723
				rlState = getStateTerm(state, stateTermUUID);
724
			}
725
		}
726
		if(isTextData){
727
			TextData textData = TextData.NewInstance(redListFeature);
728
			textData.putText(Language.GERMAN(), strRlKatValue);
729
			DescriptionElementBase descriptionElement = textData;
730
			taxonDescription.addElement(descriptionElement);
731
		}else{
732
			CategoricalData catData = CategoricalData.NewInstance(rlState, redListFeature);
733
			DescriptionElementBase descriptionElement = catData;
734
			taxonDescription.addElement(descriptionElement);
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 (strRank == null){
751
			return null;
752
		}
753
		Rank codeRank = null;
754
		try {
755
			codeRank = BfnXmlTransformer.rankCode2Rank(strRank);
756
		} catch (UnknownCdmTypeException e1) {
757
			codeRank = Rank.UNKNOWN_RANK();
758
		}
759
		//codeRank exists
760
		if ( (codeRank != null) && !codeRank.equals(Rank.UNKNOWN_RANK())){
761
			result = codeRank;
762
		}
763
		//codeRank does not exist
764
		else{
765
			result = codeRank;
766
			logger.warn("string rank used, because code rank does not exist or was not recognized: " + codeRank.getTitleCache()+" "+strRank);
767
		}
768
		return result;
769
	}
770

    
771
	/**
772
	 * @param rank
773
	 * @param strAuthor
774
	 * @param strSupplement
775
	 * @param elWissName
776
	 * @return
777
	 * @throws UnknownCdmTypeException
778
	 */
779
	private TaxonNameBase<?, ?> parseNonviralNames(Rank rank, String strAuthor, String strSupplement, Element elWissName)
780
			throws UnknownCdmTypeException {
781
		TaxonNameBase<?,?> taxonNameBase = null;
782

    
783
		String strScientificName = elWissName.getTextNormalize();
784
		/**
785
		 *
786
		 * trim strScienctificName because sometimes
787
		 * getTextNormalize() does not removes all the
788
		 * whitespaces
789
		 *
790
		 **/
791
		strScientificName = StringUtils.trim(strScientificName);
792
		strScientificName = StringUtils.remove(strScientificName, "\u00a0");
793
		strScientificName = StringUtils.remove(strScientificName, "\uc281");
794

    
795
		if(strSupplement != null && !strSupplement.isEmpty()){
796
			strScientificName = StringUtils.remove(strScientificName, strSupplement);
797
		}
798
		NonViralName<?> nonViralName = null;
799
		NonViralNameParserImpl parser = NonViralNameParserImpl.NewInstance();
800
		nonViralName = parser.parseFullName(strScientificName, nomenclaturalCode, rank);
801
		if(nonViralName.hasProblem()){
802
			for(ParserProblem p:nonViralName.getParsingProblems()){
803
				logger.warn(++parsingProblemCounter + " " +nonViralName.getTitleCache() +" "+p.toString());
804
			}
805
		}
806
		//check for parsed rank
807
		Rank parsedRank = nonViralName.getRank();
808
		if(parsedRank != rank){
809
			nonViralName.setRank(rank);
810
		}
811
		//check for parsed author
812
		String parsedAuthor = nonViralName.getAuthorshipCache();
813
		strAuthor = StringUtils.trim(strAuthor);
814
		parsedAuthor = StringUtils.trim(parsedAuthor);
815
		if(parsedAuthor.equalsIgnoreCase(strAuthor)){
816
			logger.info("Taxon " + nonViralName.getTitleCache() +":"
817
					+"\t Author field: " + strAuthor +" and parsed AuthorshipCache: "+nonViralName.getAuthorshipCache());
818
		}
819
		taxonNameBase = nonViralName;
820
		return taxonNameBase;
821
	}
822

    
823
	/**
824
	 * This method will match the BFN XML status to a distribution status
825
	 * and map it to the german federal state area. The vocabulary needs to be
826
	 * created first by the Importer, in order to map the terms correctly. Have a look
827
	 * for further details at the file BfnXmlImportAdditionalTerms.
828
	 *
829
	 *
830
     * @param taxon, for saving the distribution and its status
831
     * @param elInfoDetail, keeps the details from the import, in this case the distribution detail
832
     * @param state, import state
833
     * @param germanState, the abbreviated label for the German state
834
     *
835
     */
836
    private void createGermanDistributionStatus(Taxon taxon, Element elInfoDetail, BfnXmlImportState state,
837
            TaxonDescription taxonDescription){
838

    
839
        String strDistributionValue = elInfoDetail.getChild(BfnXmlConstants.EL_WERT).getValue();
840
        String strGermanState = elInfoDetail.getAttributeValue(BfnXmlConstants.ATT_STANDARDNAME);
841
        //match DistributionValue
842
        UUID matchedDistributionUUID = null;
843
        PresenceAbsenceTerm status = null;
844
        try {
845
            matchedDistributionUUID = BfnXmlTransformer.matchDistributionValue(strDistributionValue);
846
            DefinedTermBase load = getTermService().load(matchedDistributionUUID);
847
            if(load.isInstanceOf(PresenceAbsenceTerm.class)) {
848
                status = CdmBase.deproxy(load, PresenceAbsenceTerm.class);
849
            }else{
850
                logger.warn(strDistributionValue + " is not PresenceAbsence Term " + load.getTitleCache() + " " + load.getTermType().toString());
851
                return;
852
            }
853
        } catch (UnknownCdmTypeException e1) {
854
            logger.warn("could not match xml value "+ strDistributionValue +" to distribution status for "+strGermanState);
855
            e1.printStackTrace();
856
            return;
857
        }
858
        //load vocabulary and german state
859
        UUID vocabularyUUID = null;
860
        TermVocabulary vocabulary = null;
861
        UUID stateUUID = null;
862

    
863
        try {
864
            stateUUID = BfnXmlTransformer.getGermanStateUUID(strGermanState);
865
        } catch (UnknownCdmTypeException e1) {
866
            logger.warn("could not match state" + strGermanState + " to UUID");
867
            e1.printStackTrace();
868
            return;
869
        }
870
        NamedArea area = (NamedArea)getTermService().load(stateUUID);
871

    
872
//        try {
873
//            vocabularyUUID =  BfnXmlTransformer.getRedlistVocabularyUUID("Bundesländer");
874
//            vocabulary = getVocabularyService().load(vocabularyUUID);
875
//        } catch (UnknownCdmTypeException e) {
876
//            logger.warn("could not load vocabulary");
877
//            e.printStackTrace();
878
//            return;
879
//        }
880
//        NamedArea area = null;
881
//        for(Object term: vocabulary){
882
//            //TODO match german state
883
//            NamedArea narea = (NamedArea) term;
884
//            Set<Representation> representations = narea.getRepresentations();
885
//            for(Representation r:representations){
886
//                if(r.getAbbreviatedLabel().equalsIgnoreCase(strGermanState)){
887
//                    area = narea;
888
//                }
889
//            }
890
//
891
//        }
892
        //create new taxon description
893
        DescriptionElementBase descriptionElement = Distribution.NewInstance(area, status);
894
        taxonDescription.addElement(descriptionElement);
895
    }
896

    
897

    
898
    @Override
899
    public boolean doCheck(BfnXmlImportState state){
900
        boolean result = true;
901
        return result;
902
    }
903

    
904
	@Override
905
	protected boolean isIgnore(BfnXmlImportState state){
906
		return ! state.getConfig().isDoTaxonNames();
907
	}
908
}
(7-7/8)