View Javadoc

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.ArrayList;
13  import java.util.HashSet;
14  import java.util.Iterator;
15  import java.util.List;
16  import java.util.Set;
17  
18  import org.apache.log4j.Logger;
19  import org.jdom.Attribute;
20  import org.jdom.Element;
21  import org.jdom.Namespace;
22  import org.jdom.filter.ElementFilter;
23  import org.jdom.filter.Filter;
24  import org.springframework.stereotype.Component;
25  
26  import eu.etaxonomy.cdm.api.service.ITaxonService;
27  import eu.etaxonomy.cdm.common.ResultWrapper;
28  import eu.etaxonomy.cdm.common.XmlHelp;
29  import eu.etaxonomy.cdm.io.common.ICdmIO;
30  import eu.etaxonomy.cdm.io.common.ImportHelper;
31  import eu.etaxonomy.cdm.io.common.MapWrapper;
32  import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
33  import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
34  import eu.etaxonomy.cdm.model.name.NonViralName;
35  import eu.etaxonomy.cdm.model.name.Rank;
36  import eu.etaxonomy.cdm.model.name.TaxonNameBase;
37  import eu.etaxonomy.cdm.model.reference.IGeneric;
38  import eu.etaxonomy.cdm.model.reference.ReferenceBase;
39  import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
40  import eu.etaxonomy.cdm.model.taxon.Synonym;
41  import eu.etaxonomy.cdm.model.taxon.Taxon;
42  import eu.etaxonomy.cdm.model.taxon.TaxonBase;
43  
44  
45  /**
46   * @author a.mueller
47   *
48   */
49  @Component
50  public class TcsXmlTaxonImport  extends TcsXmlImportBase implements ICdmIO<TcsXmlImportState> {
51  	private static final Logger logger = Logger.getLogger(TcsXmlTaxonImport.class);
52  
53  	private static int modCount = 30000;
54  	
55  	public TcsXmlTaxonImport(){
56  		super();
57  	}
58  	
59  	
60  	@Override
61  	public boolean doCheck(TcsXmlImportState state){
62  		boolean result = true;
63  		logger.warn("Checking for Taxa not yet implemented");
64  		//result &= checkArticlesWithoutJournal(bmiConfig);
65  		//result &= checkPartOfJournal(bmiConfig);
66  		
67  		return result;
68  	}
69  	
70  	/**
71  	 * Computes a list of all TaxonConcept ids (ref-attribute) that are related as synonyms
72  	 * @param elTaxonConceptList
73  	 * @param success
74  	 * @return
75  	 */
76  	private Set<String> makeSynonymIds(List<Element> elTaxonConceptList, ResultWrapper<Boolean> success){
77  		//TODO use XPath
78  		
79  		 Set<String> result =  new HashSet<String>();
80  		
81  		Namespace tcsNamespace;
82  		//for each taxonConcept
83  		for (Element elTaxonConcept : elTaxonConceptList){
84  			tcsNamespace = elTaxonConcept.getNamespace();
85  			
86  			String childName = "TaxonRelationships";
87  			boolean obligatory = false;
88  			Element elTaxonRelationships = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
89  
90  			if (elTaxonRelationships == null){
91  				continue;
92  			}
93  			String tcsElementName = "TaxonRelationship";
94  			List<Element> elTaxonRelationshipList = elTaxonRelationships.getChildren(tcsElementName, tcsNamespace);
95  			for (Element elTaxonRelationship : elTaxonRelationshipList){
96  				
97  				String relationshipType = elTaxonRelationship.getAttributeValue("type");
98  				if ("has synonym".equalsIgnoreCase(relationshipType)){
99  					childName = "ToTaxonConcept";
100 					obligatory = true;
101 					Element elToTaxonConcept = XmlHelp.getSingleChildElement(success, elTaxonRelationship, childName, tcsNamespace, obligatory);
102 					
103 					String linkType = elToTaxonConcept.getAttributeValue("linkType");
104 					if (linkType == null || linkType.equals("local")){
105 						String ref = elToTaxonConcept.getAttributeValue("ref");
106 						result.add(ref);
107 					}else{
108 						logger.warn("External link types for synonym not yet implemented");
109 					}		
110 				}
111 			}
112 		}
113 		return result;
114 	}
115 	
116 	
117 	protected static final ReferenceBase unknownSec(){
118 		ReferenceFactory refFactory = ReferenceFactory.newInstance();
119 		ReferenceBase result = refFactory.newGeneric();
120 		result.setTitleCache("UNKNOWN", true);
121 		return result;
122 	}
123 	
124 	@Override
125 	public boolean doInvoke(TcsXmlImportState state){
126 		
127 		logger.info("start make TaxonConcepts ...");
128 		MapWrapper<TaxonBase> taxonMap = (MapWrapper<TaxonBase>)state.getStore(ICdmIO.TAXON_STORE);
129 		MapWrapper<TaxonNameBase<?,?>> taxonNameMap = (MapWrapper<TaxonNameBase<?,?>>)state.getStore(ICdmIO.TAXONNAME_STORE);
130 		MapWrapper<ReferenceBase> referenceMap = (MapWrapper<ReferenceBase>)state.getStore(ICdmIO.REFERENCE_STORE);
131 		ITaxonService taxonService = getTaxonService();
132 
133 		ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
134 		String childName;
135 		boolean obligatory;
136 		String idNamespace = "TaxonConcept";
137 
138 		TcsXmlImportConfigurator config = state.getConfig();
139 		Element elDataSet = getDataSetElement(config);
140 		Namespace tcsNamespace = config.getTcsXmlNamespace();
141 		
142 		childName = "TaxonConcepts";
143 		obligatory = false;
144 		Element elTaxonConcepts = XmlHelp.getSingleChildElement(success, elDataSet, childName, tcsNamespace, obligatory);
145 		
146 		String tcsElementName = "TaxonConcept";
147 		List<Element> elTaxonConceptList = elTaxonConcepts.getChildren(tcsElementName, tcsNamespace);
148 		
149 		Set<String> synonymIdSet = makeSynonymIds(elTaxonConceptList, success);
150 		//TODO make the same for the Assertions
151 		
152 		int i = 0;
153 		
154 		//for each taxonConcept
155 		for (Element elTaxonConcept : elTaxonConceptList){
156 			if ((i++ % modCount) == 0 && i > 1){ logger.info("Taxa handled: " + (i-1));}
157 			List<String> elementList = new ArrayList<String>();
158 			
159 			//create TaxonName element
160 			String strId = elTaxonConcept.getAttributeValue("id");
161 			//TODO
162 			String strConceptType = elTaxonConcept.getAttributeValue("type"); //original, revision, incomplete, aggregate, nominal
163 			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.
164 			String strForm = elTaxonConcept.getAttributeValue("form");  //anamorph, teleomorph, hybrid
165 			
166 			childName = "Name";
167 			obligatory = true;
168 			Element elName = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
169 			TaxonNameBase<?,?> taxonName = makeName(elName, null, taxonNameMap, success);
170 			elementList.add(childName.toString());
171 			
172 			//TODO how to handle
173 			childName = "Rank";
174 			obligatory = false;
175 			Element elRank = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
176 			Rank rank = TcsXmlTaxonNameImport.makeRank(elRank);
177 			if (rank != null){
178 				logger.warn("Rank in TaxonIO not yet implemented");
179 			}
180 			elementList.add(childName.toString());
181 			
182 			childName = "AccordingTo";
183 			obligatory = false;
184 			Element elAccordingTo = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
185 			ReferenceBase sec = makeAccordingTo(elAccordingTo, referenceMap, success);
186 			elementList.add(childName.toString());
187 			// TODO may sec be null?
188 			if (sec == null){
189 				sec = unknownSec();
190 			}
191 			
192 			TaxonBase taxonBase;
193 			if (synonymIdSet.contains(strId)){
194 				taxonBase = Synonym.NewInstance(taxonName, sec);
195 			}else{
196 				taxonBase = Taxon.NewInstance(taxonName, sec);	
197 			}
198 			
199 			childName = "TaxonRelationships";
200 			obligatory = false;
201 			Element elTaxonRelationships = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
202 			makeTaxonRelationships(taxonBase, elTaxonRelationships, success);
203 			elementList.add(childName.toString());
204 
205 			childName = "SpecimenCircumscription";
206 			obligatory = false;
207 			Element elSpecimenCircumscription = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
208 			makeSpecimenCircumscription(taxonBase, elSpecimenCircumscription, success);
209 			elementList.add(childName.toString());
210 
211 			childName = "CharacterCircumscription";
212 			obligatory = false;
213 			Element elCharacterCircumscription = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
214 			makeCharacterCircumscription(taxonBase, elCharacterCircumscription, success);
215 			elementList.add(childName.toString());
216 
217 			
218 			childName = "ProviderLink";
219 			obligatory = false;
220 			Element elProviderLink = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
221 			makeProviderLink(taxonBase, elProviderLink, success);
222 			elementList.add(childName.toString());
223 			
224 			childName = "ProviderSpecificData";
225 			obligatory = false;
226 			Element elProviderSpecificData = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
227 			makeProviderSpecificData(taxonBase, elProviderSpecificData, success);
228 			elementList.add(childName.toString());
229 
230 			testAdditionalElements(elTaxonConcept, elementList);
231 			ImportHelper.setOriginalSource(taxonBase, config.getSourceReference(), strId, idNamespace);
232 			taxonMap.put(strId, taxonBase);
233 			
234 		}
235 		//invokeRelations(source, cdmApp, deleteAll, taxonMap, referenceMap);
236 		logger.info(i + " taxa handled. Saving ...");
237 		taxonService.save(taxonMap.objects());
238 		logger.info("end makeTaxa ...");
239 		return success.getValue();
240 	}
241 	
242 	
243 	private boolean hasIsSynonymRelation(Element taxonConcept, Namespace rdfNamespace){
244 		boolean result = false;
245 		if (taxonConcept == null || ! "TaxonConcept".equalsIgnoreCase(taxonConcept.getName()) ){
246 			return false;
247 		}
248 		
249 		String elName = "relationshipCategory";
250 		Filter filter = new ElementFilter(elName, taxonConcept.getNamespace());
251 		Iterator<Element> relationshipCategories = taxonConcept.getDescendants(filter);
252 		while (relationshipCategories.hasNext()){
253 			Element relationshipCategory = relationshipCategories.next();
254 			Attribute resource = relationshipCategory.getAttribute("resource", rdfNamespace);
255 			String isSynonymFor = "http://rs.tdwg.org/ontology/voc/TaxonConcept#IsSynonymFor";
256 			if (resource != null && isSynonymFor.equalsIgnoreCase(resource.getValue()) ){
257 				return true;
258 			}
259 		}
260 		return result;
261 	}
262 	
263 	
264 	/**
265 	 * @param elTaxonRelationships
266 	 * @param success
267 	 */
268 	private TaxonNameBase<?, ?> makeName(Element elName, NomenclaturalCode code, MapWrapper<? extends TaxonNameBase<?,?>> objectMap, ResultWrapper<Boolean> success){
269 		TaxonNameBase<?, ?> result = null;
270 		if (elName != null){
271 			//scientific
272 			try {
273 				String strScientific = elName.getAttributeValue("scientific");
274 				boolean scientific = Boolean.valueOf(strScientific);
275 				if (! scientific){
276 					//TODO
277 					logger.warn("Non scientific names not yet implemented");
278 					success.setValue(false);
279 				}
280 			} catch (Exception e) {
281 				logger.warn("Value for scientific is not boolean");
282 			}
283 			String language = elName.getAttributeValue("language");
284 			//TODO
285 			//Language
286 			if (language != null){
287 				logger.warn("language for name not yet implemented");	
288 			}
289 			Class<? extends IdentifiableEntity> clazz = (Class<? extends IdentifiableEntity>)NonViralName.class;
290 			if (code != null){
291 				clazz = code.getCdmClass();
292 			}
293 			result = (TaxonNameBase<?,?>)makeReferenceType (elName, clazz , objectMap, success);
294 			if(result == null){
295 				logger.warn("Name not found");
296 				success.setValue(false);
297 			}
298 		}else{
299 			logger.warn("Name element is null");
300 		}
301 		return result;
302 	}
303 	
304 	
305 	/**
306 	 * @param elTaxonRelationships
307 	 * @param success
308 	 */
309 	private void makeTaxonRelationships(TaxonBase name, Element elTaxonRelationships, ResultWrapper<Boolean> success){
310 		//TaxonRelationships are handled in TcsXmlTaxonRelationsImport
311 		return;
312 	}
313 	
314 
315 	
316 	private void makeSpecimenCircumscription(TaxonBase name, Element elSpecimenCircumscription, ResultWrapper<Boolean> success){
317 		if (elSpecimenCircumscription != null){
318 			logger.warn("makeProviderLink not yet implemented");
319 			success.setValue(false);
320 		}
321 	}
322 	
323 	
324 	private void makeCharacterCircumscription(TaxonBase name, Element elCharacterCircumscription, ResultWrapper<Boolean> success){
325 		if (elCharacterCircumscription != null){
326 			logger.warn("makeProviderLink not yet implemented");
327 			success.setValue(false);
328 		}
329 	}
330 	
331 	private void makeProviderLink(TaxonBase name, Element elProviderLink, ResultWrapper<Boolean> success){
332 		if (elProviderLink != null){
333 			logger.warn("makeProviderLink not yet implemented");
334 			success.setValue(false);
335 		}
336 	}
337 	
338 
339 	private void makeProviderSpecificData(TaxonBase name, Element elProviderSpecificData, ResultWrapper<Boolean> success){
340 		if (elProviderSpecificData != null){
341 			logger.warn("makeProviderLink not yet implemented");
342 			success.setValue(false);
343 		}
344 	}
345 	
346 	
347 	
348 	/* (non-Javadoc)
349 	 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
350 	 */
351 	protected boolean isIgnore(TcsXmlImportState state){
352 		return ! state.getConfig().isDoTaxa();
353 	}
354 
355 
356 }