Project

General

Profile

Download (16.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2009 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.tcsxml.in;
11

    
12
import java.util.HashSet;
13
import java.util.List;
14
import java.util.Map;
15
import java.util.Set;
16

    
17
import org.apache.log4j.Logger;
18
import org.jdom.Element;
19
import org.jdom.Namespace;
20
import org.springframework.stereotype.Component;
21

    
22
import eu.etaxonomy.cdm.common.ResultWrapper;
23
import eu.etaxonomy.cdm.common.XmlHelp;
24
import eu.etaxonomy.cdm.io.common.ICdmIO;
25
import eu.etaxonomy.cdm.io.common.MapWrapper;
26
import eu.etaxonomy.cdm.io.tcsxml.TcsXmlTransformer;
27
import eu.etaxonomy.cdm.model.common.CdmBase;
28
import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
29
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
30
import eu.etaxonomy.cdm.model.description.TaxonDescription;
31
import eu.etaxonomy.cdm.model.name.NonViralName;
32
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
33
import eu.etaxonomy.cdm.model.reference.Reference;
34
import eu.etaxonomy.cdm.model.taxon.Synonym;
35
import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
36
import eu.etaxonomy.cdm.model.taxon.Taxon;
37
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
38
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
39
import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
40
import eu.etaxonomy.cdm.model.taxon.Classification;
41
import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
42

    
43

    
44
/**
45
 * @author a.mueller
46
 *
47
 */
48
@Component
49
public class TcsXmlTaxonRelationsImport extends TcsXmlImportBase implements ICdmIO<TcsXmlImportState> {
50
	private static final Logger logger = Logger.getLogger(TcsXmlTaxonRelationsImport.class);
51

    
52
	private static int modCount = 30000;
53

    
54
	public TcsXmlTaxonRelationsImport(){
55
		super();
56
	}
57
	
58
	@Override
59
	public boolean doCheck(TcsXmlImportState state){
60
		boolean result = true;
61
		logger.warn("Checking for TaxonRelations not yet implemented");
62
		logger.warn("Creation of homotypic relations is still problematic");
63
		//result &= checkArticlesWithoutJournal(bmiConfig);
64
		//result &= checkPartOfJournal(bmiConfig);
65
		
66
		return result;
67
	}
68
	
69
	@Override
70
	public void doInvoke(TcsXmlImportState state){ 
71
	
72
		
73
		logger.info("start make taxon relations ...");
74
		MapWrapper<TaxonBase> taxonMap = (MapWrapper<TaxonBase>)state.getStore(ICdmIO.TAXON_STORE);
75
		MapWrapper<TaxonNameBase<?,?>> taxonNameMap = (MapWrapper<TaxonNameBase<?,?>>)state.getStore(ICdmIO.TAXONNAME_STORE);
76
		MapWrapper<Reference> referenceMap = (MapWrapper<Reference>)state.getStore(ICdmIO.REFERENCE_STORE);
77

    
78
		Set<TaxonBase> taxonStore = new HashSet<TaxonBase>();
79

    
80
		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
81
		String childName;
82
		boolean obligatory;
83
		String idNamespace = "TaxonRelation";
84

    
85
		TcsXmlImportConfigurator config = state.getConfig();
86
		Element elDataSet = super.getDataSetElement(config);
87
		Namespace tcsNamespace = config.getTcsXmlNamespace();
88
		
89
		childName = "TaxonConcepts";
90
		obligatory = false;
91
		Element elTaxonConcepts = XmlHelp.getSingleChildElement(success, elDataSet, childName, tcsNamespace, obligatory);
92
		
93
		childName = "TaxonConcept";
94
		List<Element> elTaxonConceptList = elTaxonConcepts.getChildren(childName, tcsNamespace);
95
		
96
		int i = 0;
97
		int taxonRelCount = 0;
98
		
99
		//for each taxonConcept
100
		for (Element elTaxonConcept : elTaxonConceptList){
101
			if ((i++ % modCount) == 0){ logger.info("Taxa handled: " + (i-1));}
102
			taxonRelCount += makeTaxonConcept(state, taxonMap, taxonStore, elTaxonConcept, tcsNamespace, success);	
103
		}//elTaxonConcept
104
	
105
		//TaxonRelationshipAssertions
106
		taxonRelCount += makeTaxonRelationshipAssertion(state, taxonMap, referenceMap, taxonStore, elDataSet, tcsNamespace, success);	
107
		
108
		logger.info("Taxa to save: " + taxonStore.size());
109
		getTaxonService().save(taxonStore);
110
		
111
		logger.info("end make taxon relations ...");
112
		if (!success.getValue()){
113
			state.setUnsuccessfull();
114
		}
115
		return;
116
	}
117
	
118
	private int makeTaxonConcept(TcsXmlImportState state, MapWrapper<TaxonBase> taxonMap, Set<TaxonBase> taxonStore, Element elTaxonConcept, Namespace tcsNamespace, ResultWrapper<Boolean> success){
119
		int taxonRelCount = 0;
120
		
121
		String childName = "TaxonRelationships";
122
		boolean obligatory = false;
123
		Element elTaxonRelationships = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
124
		
125
		if (elTaxonRelationships != null){
126
			//Relationships
127
			String tcsElementName = "TaxonRelationship";
128
			List<Element> elTaxonRelationshipList = elTaxonRelationships.getChildren(tcsElementName, tcsNamespace);
129

    
130
			for (Element elTaxonRelationship: elTaxonRelationshipList){
131
				taxonRelCount++;
132
				logger.debug("TaxonRelationship "+  taxonRelCount);
133
				
134
				String strId = elTaxonConcept.getAttributeValue("id");
135
				//TODO
136
//				String strConceptType = elTaxonConcept.getAttributeValue("type"); //original, revision, incomplete, aggregate, nominal
137
//				String strPrimary = elTaxonConcept.getAttributeValue("primary"); //If primary='true' the concept is the first level response to a query. If 'false' the concept may be a secondary concept linked directly or indirectly to the definition of a primary concept.
138
//				String strForm = elTaxonConcept.getAttributeValue("form");  //anamorph, teleomorph, hybrid
139
				
140
				TaxonBase fromTaxon = taxonMap.get(strId);
141
				makeRelationshipType(state, elTaxonRelationship, taxonMap, taxonStore, fromTaxon, success);
142
			
143
				if (fromTaxon instanceof Taxon){
144
					makeHomotypicSynonymRelations((Taxon)fromTaxon);
145
				}
146
			}// end Relationship
147
		}
148
		return taxonRelCount;
149
	}
150

    
151
	private int makeTaxonRelationshipAssertion(
152
			TcsXmlImportState state, 
153
			MapWrapper<TaxonBase> taxonMap,
154
			MapWrapper<Reference> referenceMap,
155
			Set<TaxonBase> taxonStore, 
156
			Element elDataSet, 
157
			Namespace tcsNamespace, 
158
			ResultWrapper<Boolean> success){
159
		
160
		int i = 0;
161
		String childName = "TaxonRelationshipAssertions";
162
		boolean obligatory = false;
163
		Element elTaxonRelationshipAssertions = XmlHelp.getSingleChildElement(success, elDataSet, childName, tcsNamespace, obligatory);
164
		if(elTaxonRelationshipAssertions == null){
165
			return 0;
166
		}
167
		
168
		childName = "TaxonRelationshipAssertion";
169
		List<Element> elTaxonRelationshipAssertionList = elTaxonRelationshipAssertions.getChildren(childName, tcsNamespace);
170
		//for each taxon relationship assertion
171
		for (Element elTaxonRelationshipAssertion : elTaxonRelationshipAssertionList){
172
			if ((i++ % modCount) == 0){ logger.info("TaxonRelationshipAssertions handled: " + (i-1));}
173
			String strId = elTaxonRelationshipAssertion.getAttributeValue("id");
174
			//TODO id
175
			
176
			childName = "AccordingTo";
177
			obligatory = true;
178
			Element elAccordingTo = XmlHelp.getSingleChildElement(success, elTaxonRelationshipAssertion, childName, tcsNamespace, obligatory);
179
			Reference ref = makeAccordingTo(elAccordingTo, referenceMap, success);
180
			
181
			childName = "FromTaxonConcept";
182
			obligatory = true;
183
			Element elFromTaxonConcept = XmlHelp.getSingleChildElement(success, elTaxonRelationshipAssertion, childName, tcsNamespace, obligatory);
184

    
185
			Class<? extends TaxonBase> clazz = Taxon.class;
186
			//TODO if synonym
187
			TaxonBase fromTaxon = makeReferenceType(elFromTaxonConcept, clazz, taxonMap, success);
188
			
189
			makeRelationshipType(state, elTaxonRelationshipAssertion, taxonMap, taxonStore, fromTaxon, success);
190
		}//elTaxonRelationshipAssertion
191
		
192
		return i;
193
	}
194
	
195
	
196
	/**
197
	 * Handles the TCS RelationshipType element.
198
	 * @param tcsConfig
199
	 * @param elRelationship
200
	 * @param taxonMap
201
	 * @param taxonStore
202
	 * @param fromTaxon
203
	 * @param success
204
	 */
205
	private void makeRelationshipType(
206
			TcsXmlImportState state
207
			, Element elRelationship 
208
			, MapWrapper<TaxonBase> taxonMap
209
			, Set<TaxonBase> taxonStore
210
			, TaxonBase fromTaxon
211
			, ResultWrapper<Boolean> success
212
			){
213
	
214
		if (elRelationship == null){
215
			success.setValue(false);
216
		}
217
		String strRelType = elRelationship.getAttributeValue("type");
218
		
219
		
220
		try {
221
			ResultWrapper<Boolean> isInverse = new ResultWrapper<Boolean>();
222
			isInverse.setValue(false);
223
			if ("has vernacular".equalsIgnoreCase(strRelType)){
224
				handleVernacular(success, state, elRelationship, fromTaxon);
225
			}else{
226
				RelationshipTermBase<?> relType = TcsXmlTransformer.tcsRelationshipType2Relationship(strRelType, isInverse);
227
				
228
				//toTaxon (should be part of relationshipType)
229
				boolean isSynonym = (relType instanceof SynonymRelationshipType);
230
				TaxonBase toTaxon = getToTaxon(elRelationship, taxonMap, isSynonym, success);
231
				
232
				if (toTaxon != null && fromTaxon != null){
233
					//exchange taxa if relationship is inverse
234
					if (isInverse.getValue() == true ){
235
						TaxonBase tmp = toTaxon;
236
						toTaxon = fromTaxon;
237
						fromTaxon = tmp;
238
					}
239
					
240
					//Create relationship
241
					if (! (toTaxon instanceof Taxon)){
242
						logger.warn("TaxonBase toTaxon is not of Type 'Taxon'. Relationship is not added.");
243
						success.setValue(false);
244
					}else{
245
						Taxon taxonTo = (Taxon)toTaxon;
246
						Reference citation = null;
247
						String microReference = null;
248
						if (relType instanceof SynonymRelationshipType){
249
							SynonymRelationshipType synRelType = (SynonymRelationshipType)relType;
250
							if (! (fromTaxon instanceof Synonym )){
251
								logger.warn("TaxonBase fromTaxon is not of Type 'Synonym'. Relationship is not added.");
252
								success.setValue(false);
253
							}else{
254
								Synonym synonym = (Synonym)fromTaxon;
255
								TaxonNameBase<?,?> synName = synonym.getName();
256
								TaxonNameBase<?,?> accName = taxonTo.getName();
257
								if (synName != null && accName != null && synName.isHomotypic(accName)
258
											&& ( synRelType.equals(SynonymRelationshipType.SYNONYM_OF()))){
259
									synRelType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF(); 
260
								}
261
								if (! relationExists(taxonTo, synonym, synRelType)){
262
									taxonTo.addSynonym(synonym, synRelType,  citation, microReference);	
263
								}else{
264
									//TODO citation, microReference
265
									//TODO different synRelTypes -> warning
266
									success.setValue(false);
267
								}
268
							}
269
						}else if (relType instanceof TaxonRelationshipType){
270
							makeTaxonRelationship(state, (TaxonRelationshipType)relType, fromTaxon, taxonTo, citation, microReference, success);
271
						}else{
272
							logger.warn("Unknown Relationshiptype");
273
							success.setValue(false);
274
						}
275
						taxonStore.add(toTaxon);
276
					}
277
				}else{
278
					if (toTaxon == null){
279
						logger.warn("toTaxon (" + /*strToTaxon + */ ") could  not be found in taxonMap. Relationship of type " + strRelType + " was not added to CDM");
280
					}
281
					if (fromTaxon == null){
282
						logger.warn("fromTaxon (" + /*strTaxonAbout + */") could not be found in taxonMap. Relationship was not added to CDM");
283
					}
284
					success.setValue(false);
285
				}
286
			}		
287
		} catch (UnknownCdmTypeException e) {
288
			//TODO
289
			logger.warn("relationshipType " + strRelType + " not yet implemented");
290
			success.setValue(false);
291
		}
292
		return;
293
	}
294
	
295
	private void handleVernacular(ResultWrapper<Boolean> success, TcsXmlImportState state, Element elRelationship, TaxonBase taxonBase) {
296
		if (! taxonBase.isInstanceOf(Taxon.class)){
297
			logger.warn("From Taxon is not of type Taxon but of type " +  taxonBase.getClass().getSimpleName());
298
			success.setValue(false);
299
			return;
300
		}else{
301
			Taxon taxon = CdmBase.deproxy(taxonBase, Taxon.class);
302
			Map<String, CommonTaxonName> commonNameMap = state.getCommonNameMap();
303
			CommonTaxonName commonTaxonName = getCommonName(elRelationship, commonNameMap, success);
304
			TaxonDescription description = getDescription(taxon);
305
			description.addElement(commonTaxonName);
306
		}
307
	}
308
	
309
	private TaxonDescription getDescription(Taxon taxon) {
310
		if (taxon.getDescriptions().isEmpty()){
311
			return TaxonDescription.NewInstance(taxon);
312
		}else{
313
			//TODO only if the description represents this TCS file
314
			return taxon.getDescriptions().iterator().next();
315
		}
316
	}
317

    
318
	private CommonTaxonName getCommonName(Element elTaxonRelationship, Map<String, CommonTaxonName> commonNameMap, ResultWrapper<Boolean> success){
319
		CommonTaxonName result = null;
320
		if (elTaxonRelationship == null || commonNameMap == null){
321
			success.setValue(false);
322
		}else{
323
			String childName = "ToTaxonConcept";
324
			boolean obligatory = true;
325
			Element elToTaxonConcept = XmlHelp.getSingleChildElement(success, elTaxonRelationship, childName, elTaxonRelationship.getNamespace(), obligatory);
326
			
327
			String linkType = elToTaxonConcept.getAttributeValue("linkType");
328
			if (linkType == null || linkType.equals("local")){
329
				String ref = elToTaxonConcept.getAttributeValue("ref");
330
				if (ref != null){
331
					result = commonNameMap.get(ref);
332
				}else{
333
					logger.warn("Non ref not yet implemented for vernacular name relationship");
334
				}
335
			}else{
336
				logger.warn("External link types for vernacular name not yet implemented");
337
			}
338
		}
339
		return result;
340
	}
341

    
342
	private void makeTaxonRelationship(TcsXmlImportState state, TaxonRelationshipType relType, TaxonBase fromTaxon, Taxon taxonTo, Reference citation, String microReference, ResultWrapper<Boolean> success){
343
		TaxonRelationshipType taxRelType = (TaxonRelationshipType)relType;
344
		if (! (fromTaxon instanceof Taxon )){
345
			logger.warn("TaxonBase fromTaxon " + /*strTaxonAbout +*/ "is not of Type 'Taxon'. Relationship is not added.");
346
			success.setValue(false);
347
		}else{
348
			Taxon taxonFrom = (Taxon)fromTaxon;
349
			if (relType.equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())){
350
				makeTaxonomicallyIncluded(state, taxonTo, taxonFrom, citation, microReference);
351
			}else{
352
				taxonFrom.addTaxonRelation(taxonTo, taxRelType, citation, microReference);
353
			}
354
		}
355
	}
356
	
357
	private boolean makeTaxonomicallyIncluded(TcsXmlImportState state, Taxon toTaxon, Taxon fromTaxon, Reference citation, String microCitation){
358
		Reference sec = toTaxon.getSec();
359
		Classification tree = state.getTree(sec);
360
		if (tree == null){
361
			tree = makeTree(state, sec);
362
		}
363
		TaxonNode childNode = tree.addParentChild(toTaxon, fromTaxon, citation, microCitation);
364
		return (childNode != null);
365
	}
366
	
367
	
368
	private TaxonBase getToTaxon(Element elTaxonRelationship, MapWrapper<TaxonBase> map, boolean isSynonym, ResultWrapper<Boolean> success){
369
		TaxonBase result = null;
370
		if (elTaxonRelationship == null || map == null){
371
			success.setValue(false);
372
		}else{
373
			String childName = "ToTaxonConcept";
374
			boolean obligatory = true;
375
			Element elToTaxonConcept = XmlHelp.getSingleChildElement(success, elTaxonRelationship, childName, elTaxonRelationship.getNamespace(), obligatory);
376
			
377
			String linkType = elToTaxonConcept.getAttributeValue("linkType");
378
			if (linkType == null || linkType.equals("local")){
379
				String ref = elToTaxonConcept.getAttributeValue("ref");
380
				if (ref != null){
381
					result = map.get(ref);
382
				}else{
383
					String title = elToTaxonConcept.getTextNormalize();
384
					//TODO synonym?
385
					TaxonNameBase<?,?> taxonName = NonViralName.NewInstance(null);
386
					taxonName.setTitleCache(title, true);
387
					logger.warn("Free text related taxon seems to be bug in TCS");
388
					if (isSynonym){
389
						result = Synonym.NewInstance(taxonName, TcsXmlTaxonImport.unknownSec());
390
					}else{
391
						result = Taxon.NewInstance(taxonName, TcsXmlTaxonImport.unknownSec());	
392
					}
393
					result.setTitleCache(title, true);
394
				}
395
			}else{
396
				logger.warn("External link types for synonym not yet implemented");
397
			}
398
		}
399
		return result;
400
	}
401
	
402

    
403
	
404
	
405
	
406
	private boolean relationExists(Taxon taxonTo, Synonym synonym, SynonymRelationshipType synRelType){
407
		if (synonym == null){
408
			return false;
409
		}
410
		if (synonym.getRelationType(taxonTo).size() > 0){
411
			Set<SynonymRelationshipType> relTypeList = synonym.getRelationType(taxonTo);
412
			if (relTypeList.contains(synRelType)){
413
				return true;
414
			}else{
415
				logger.warn("Taxon-Synonym pair has 2 different SynonymRelationships. This is against the rules");
416
				return false;
417
			}
418
		}else{
419
			return false;
420
		}
421
	}
422

    
423
	private boolean makeHomotypicSynonymRelations(Taxon aboutTaxon){
424
		TaxonNameBase<?,?> aboutName = aboutTaxon.getName();
425
		if (aboutName != null){
426
			Set<TaxonNameBase> typifiedNames = aboutName.getHomotypicalGroup().getTypifiedNames();
427
			for (TaxonNameBase<?,?> typifiedName : typifiedNames){
428
				//TODO check if name is part of this tcs file
429
				if (typifiedName.equals(aboutName)){
430
					continue;
431
				}
432
				Set<Synonym> syns = typifiedName.getSynonyms();
433
				for(Synonym syn:syns){
434
					aboutTaxon.addSynonym(syn, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF());
435
				}
436
			}
437
		}
438
		return true;
439
	}
440
	
441
	/* (non-Javadoc)
442
	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
443
	 */
444
	protected boolean isIgnore(TcsXmlImportState state){
445
		return ! state.getConfig().isDoRelTaxa();
446
	}
447
	
448
}
(11-11/11)