Merged in changes from cate-development branch and upgraded to spring 3.0.0.RC1
[cdmlib.git] / cdmlib-io / src / main / java / eu / etaxonomy / cdm / io / tcsxml / in / TcsXmlTaxonRelationsImport.java
1 /**
2 *
3 */
4 package eu.etaxonomy.cdm.io.tcsxml.in;
5
6 import java.util.HashSet;
7 import java.util.List;
8 import java.util.Set;
9
10 import org.apache.log4j.Logger;
11 import org.jdom.Element;
12 import org.jdom.Namespace;
13 import org.springframework.stereotype.Component;
14
15 import eu.etaxonomy.cdm.common.ResultWrapper;
16 import eu.etaxonomy.cdm.common.XmlHelp;
17 import eu.etaxonomy.cdm.io.common.ICdmIO;
18 import eu.etaxonomy.cdm.io.common.MapWrapper;
19 import eu.etaxonomy.cdm.io.tcsxml.TcsXmlTransformer;
20 import eu.etaxonomy.cdm.model.common.RelationshipTermBase;
21 import eu.etaxonomy.cdm.model.name.NonViralName;
22 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
23 import eu.etaxonomy.cdm.model.reference.ReferenceBase;
24 import eu.etaxonomy.cdm.model.taxon.Synonym;
25 import eu.etaxonomy.cdm.model.taxon.SynonymRelationshipType;
26 import eu.etaxonomy.cdm.model.taxon.Taxon;
27 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
28 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
29 import eu.etaxonomy.cdm.model.taxon.TaxonomicTree;
30 import eu.etaxonomy.cdm.strategy.exceptions.UnknownCdmTypeException;
31
32
33 /**
34 * @author a.mueller
35 *
36 */
37 @Component
38 public class TcsXmlTaxonRelationsImport extends TcsXmlImportBase implements ICdmIO<TcsXmlImportState> {
39 private static final Logger logger = Logger.getLogger(TcsXmlTaxonRelationsImport.class);
40
41 private static int modCount = 30000;
42
43 public TcsXmlTaxonRelationsImport(){
44 super();
45 }
46
47 @Override
48 public boolean doCheck(TcsXmlImportState state){
49 boolean result = true;
50 logger.warn("Checking for TaxonRelations not yet implemented");
51 logger.warn("Creation of homotypic relations is still problematic");
52 //result &= checkArticlesWithoutJournal(bmiConfig);
53 //result &= checkPartOfJournal(bmiConfig);
54
55 return result;
56 }
57
58 @Override
59 public boolean doInvoke(TcsXmlImportState state){
60
61
62 logger.info("start make taxon relations ...");
63 MapWrapper<TaxonBase> taxonMap = (MapWrapper<TaxonBase>)state.getStore(ICdmIO.TAXON_STORE);
64 MapWrapper<TaxonNameBase<?,?>> taxonNameMap = (MapWrapper<TaxonNameBase<?,?>>)state.getStore(ICdmIO.TAXONNAME_STORE);
65 MapWrapper<ReferenceBase> referenceMap = (MapWrapper<ReferenceBase>)state.getStore(ICdmIO.REFERENCE_STORE);
66
67 Set<TaxonBase> taxonStore = new HashSet<TaxonBase>();
68
69 ResultWrapper<Boolean> success = ResultWrapper.NewInstance(true);
70 String childName;
71 boolean obligatory;
72 String idNamespace = "TaxonRelation";
73
74 TcsXmlImportConfigurator config = state.getConfig();
75 Element elDataSet = super.getDataSetElement(config);
76 Namespace tcsNamespace = config.getTcsXmlNamespace();
77
78 childName = "TaxonConcepts";
79 obligatory = false;
80 Element elTaxonConcepts = XmlHelp.getSingleChildElement(success, elDataSet, childName, tcsNamespace, obligatory);
81
82 childName = "TaxonConcept";
83 List<Element> elTaxonConceptList = elTaxonConcepts.getChildren(childName, tcsNamespace);
84
85 int i = 0;
86 int taxonRelCount = 0;
87
88 //for each taxonConcept
89 for (Element elTaxonConcept : elTaxonConceptList){
90 if ((i++ % modCount) == 0){ logger.info("Taxa handled: " + (i-1));}
91 taxonRelCount += makeTaxonConcept(state, taxonMap, taxonStore, elTaxonConcept, tcsNamespace, success);
92 }//elTaxonConcept
93
94 //TaxonRelationshipAssertions
95 taxonRelCount += makeTaxonRelationshipAssertion(state, taxonMap, referenceMap, taxonStore, elDataSet, tcsNamespace, success);
96
97 logger.info("Taxa to save: " + taxonStore.size());
98 getTaxonService().save(taxonStore);
99
100 logger.info("end make taxon relations ...");
101 return success.getValue();
102 }
103
104 private int makeTaxonConcept(TcsXmlImportState state, MapWrapper<TaxonBase> taxonMap, Set<TaxonBase> taxonStore, Element elTaxonConcept, Namespace tcsNamespace, ResultWrapper<Boolean> success){
105 int taxonRelCount = 0;
106
107 String childName = "TaxonRelationships";
108 boolean obligatory = false;
109 Element elTaxonRelationships = XmlHelp.getSingleChildElement(success, elTaxonConcept, childName, tcsNamespace, obligatory);
110
111 if (elTaxonRelationships != null){
112 //Relationships
113 String tcsElementName = "TaxonRelationship";
114 List<Element> elTaxonRelationshipList = elTaxonRelationships.getChildren(tcsElementName, tcsNamespace);
115
116 for (Element elTaxonRelationship: elTaxonRelationshipList){
117 taxonRelCount++;
118 logger.debug("TaxonRelationship "+ taxonRelCount);
119
120 String strId = elTaxonConcept.getAttributeValue("id");
121 //TODO
122 // String strConceptType = elTaxonConcept.getAttributeValue("type"); //original, revision, incomplete, aggregate, nominal
123 // 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.
124 // String strForm = elTaxonConcept.getAttributeValue("form"); //anamorph, teleomorph, hybrid
125
126 TaxonBase fromTaxon = taxonMap.get(strId);
127 makeRelationshipType(state, elTaxonRelationship, taxonMap, taxonStore, fromTaxon, success);
128
129 if (fromTaxon instanceof Taxon){
130 makeHomotypicSynonymRelations((Taxon)fromTaxon);
131 }
132 }// end Relationship
133 }
134 return taxonRelCount;
135 }
136
137 private int makeTaxonRelationshipAssertion(
138 TcsXmlImportState state,
139 MapWrapper<TaxonBase> taxonMap,
140 MapWrapper<ReferenceBase> referenceMap,
141 Set<TaxonBase> taxonStore,
142 Element elDataSet,
143 Namespace tcsNamespace,
144 ResultWrapper<Boolean> success){
145
146 int i = 0;
147 String childName = "TaxonRelationshipAssertions";
148 boolean obligatory = false;
149 Element elTaxonRelationshipAssertions = XmlHelp.getSingleChildElement(success, elDataSet, childName, tcsNamespace, obligatory);
150 if(elTaxonRelationshipAssertions == null){
151 return 0;
152 }
153
154 childName = "TaxonRelationshipAssertion";
155 List<Element> elTaxonRelationshipAssertionList = elTaxonRelationshipAssertions.getChildren(childName, tcsNamespace);
156 //for each taxon relationship assertion
157 for (Element elTaxonRelationshipAssertion : elTaxonRelationshipAssertionList){
158 if ((i++ % modCount) == 0){ logger.info("TaxonRelationshipAssertions handled: " + (i-1));}
159 String strId = elTaxonRelationshipAssertion.getAttributeValue("id");
160 //TODO id
161
162 childName = "AccordingTo";
163 obligatory = true;
164 Element elAccordingTo = XmlHelp.getSingleChildElement(success, elTaxonRelationshipAssertion, childName, tcsNamespace, obligatory);
165 ReferenceBase ref = makeAccordingTo(elAccordingTo, referenceMap, success);
166
167 childName = "FromTaxonConcept";
168 obligatory = true;
169 Element elFromTaxonConcept = XmlHelp.getSingleChildElement(success, elTaxonRelationshipAssertion, childName, tcsNamespace, obligatory);
170
171 Class<? extends TaxonBase> clazz = Taxon.class;
172 //TODO if synonym
173 TaxonBase fromTaxon = makeReferenceType(elFromTaxonConcept, clazz, taxonMap, success);
174
175 makeRelationshipType(state, elTaxonRelationshipAssertion, taxonMap, taxonStore, fromTaxon, success);
176 }//elTaxonRelationshipAssertion
177
178 return i;
179 }
180
181
182 /**
183 * Handles the TCS RelationshipType element.
184 * @param tcsConfig
185 * @param elRelationship
186 * @param taxonMap
187 * @param taxonStore
188 * @param fromTaxon
189 * @param success
190 */
191 private void makeRelationshipType(
192 TcsXmlImportState state
193 , Element elRelationship
194 , MapWrapper<TaxonBase> taxonMap
195 , Set<TaxonBase> taxonStore
196 , TaxonBase fromTaxon
197 , ResultWrapper<Boolean> success
198 ){
199
200 if (elRelationship == null){
201 success.setValue(false);
202 }
203 String strRelType = elRelationship.getAttributeValue("type");
204
205
206 try {
207 ResultWrapper<Boolean> isInverse = new ResultWrapper<Boolean>();
208 isInverse.setValue(false);
209 RelationshipTermBase<?> relType = TcsXmlTransformer.tcsRelationshipType2Relationship(strRelType, isInverse);
210
211 //toTaxon (should be part of relationshipType)
212 boolean isSynonym = (relType instanceof SynonymRelationshipType);
213 TaxonBase toTaxon = getToTaxon(elRelationship, taxonMap, isSynonym, success);
214
215 if (toTaxon != null && fromTaxon != null){
216 //exchange taxa if relationship is inverse
217 if (isInverse.getValue() == true ){
218 TaxonBase tmp = toTaxon;
219 toTaxon = fromTaxon;
220 fromTaxon = tmp;
221 }
222
223 //Create relationship
224 if (! (toTaxon instanceof Taxon)){
225 logger.warn("TaxonBase toTaxon is not of Type 'Taxon'. Relationship is not added.");
226 success.setValue(false);
227 }else{
228 Taxon taxonTo = (Taxon)toTaxon;
229 ReferenceBase citation = null;
230 String microReference = null;
231 if (relType instanceof SynonymRelationshipType){
232 SynonymRelationshipType synRelType = (SynonymRelationshipType)relType;
233 if (! (fromTaxon instanceof Synonym )){
234 logger.warn("TaxonBase fromTaxon is not of Type 'Synonym'. Relationship is not added.");
235 success.setValue(false);
236 }else{
237 Synonym synonym = (Synonym)fromTaxon;
238 TaxonNameBase<?,?> synName = synonym.getName();
239 TaxonNameBase<?,?> accName = taxonTo.getName();
240 if (synName != null && accName != null && synName.isHomotypic(accName)
241 && ( synRelType.equals(SynonymRelationshipType.SYNONYM_OF()))){
242 synRelType = SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF();
243 }
244 if (! relationExists(taxonTo, synonym, synRelType)){
245 taxonTo.addSynonym(synonym, synRelType, citation, microReference);
246 }else{
247 //TODO citation, microReference
248 //TODO different synRelTypes -> warning
249 success.setValue(false);
250 }
251 }
252 }else if (relType instanceof TaxonRelationshipType){
253 makeTaxonRelationship(state, (TaxonRelationshipType)relType, fromTaxon, taxonTo, citation, microReference, success);
254 }else{
255 logger.warn("Unknown Relationshiptype");
256 success.setValue(false);
257 }
258 taxonStore.add(toTaxon);
259 }
260 }else{
261 if (toTaxon == null){
262 logger.warn("toTaxon (" + /*strToTaxon + */ ") could not be found in taxonMap. Relationship of type " + strRelType + " was not added to CDM");
263 }
264 if (fromTaxon == null){
265 logger.warn("fromTaxon (" + /*strTaxonAbout + */") could not be found in taxonMap. Relationship was not added to CDM");
266 }
267 success.setValue(false);
268 }
269
270 } catch (UnknownCdmTypeException e) {
271 //TODO
272 logger.warn("relationshipType " + strRelType + " not yet implemented");
273 success.setValue(false);
274 }
275 return;
276 }
277
278 private void makeTaxonRelationship(TcsXmlImportState state, TaxonRelationshipType relType, TaxonBase fromTaxon, Taxon taxonTo, ReferenceBase citation, String microReference, ResultWrapper<Boolean> success){
279 TaxonRelationshipType taxRelType = (TaxonRelationshipType)relType;
280 if (! (fromTaxon instanceof Taxon )){
281 logger.warn("TaxonBase fromTaxon " + /*strTaxonAbout +*/ "is not of Type 'Taxon'. Relationship is not added.");
282 success.setValue(false);
283 }else{
284 Taxon taxonFrom = (Taxon)fromTaxon;
285 if (relType.equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())){
286 makeTaxonomicallyIncluded(state, taxonTo, taxonFrom, citation, microReference);
287 }
288 taxonFrom.addTaxonRelation(taxonTo, taxRelType, citation, microReference);
289 }
290 }
291
292 private boolean makeTaxonomicallyIncluded(TcsXmlImportState state, Taxon toTaxon, Taxon fromTaxon, ReferenceBase citation, String microCitation){
293 boolean success = true;
294 ReferenceBase sec = toTaxon.getSec();
295 TaxonomicTree tree = state.getTree(sec);
296 if (tree == null){
297 tree = makeTree(state, sec);
298 }
299 success = tree.addParentChild(toTaxon, fromTaxon, citation, microCitation);
300 return success;
301 }
302
303
304 private TaxonBase getToTaxon(Element elTaxonRelationship, MapWrapper<TaxonBase> map, boolean isSynonym, ResultWrapper<Boolean> success){
305 TaxonBase result = null;
306 if (elTaxonRelationship == null || map == null){
307 success.setValue(false);
308 }else{
309 String childName = "ToTaxonConcept";
310 boolean obligatory = true;
311 Element elToTaxonConcept = XmlHelp.getSingleChildElement(success, elTaxonRelationship, childName, elTaxonRelationship.getNamespace(), obligatory);
312
313 String linkType = elToTaxonConcept.getAttributeValue("linkType");
314 if (linkType == null || linkType.equals("local")){
315 String ref = elToTaxonConcept.getAttributeValue("ref");
316 if (ref != null){
317 result = map.get(ref);
318 }else{
319 String title = elToTaxonConcept.getTextNormalize();
320 //TODO synonym?
321 TaxonNameBase<?,?> taxonName = NonViralName.NewInstance(null);
322 taxonName.setTitleCache(title);
323 logger.warn("Free text related taxon seems to be bug in TCS");
324 if (isSynonym){
325 result = Synonym.NewInstance(taxonName, TcsXmlTaxonImport.unknownSec());
326 }else{
327 result = Taxon.NewInstance(taxonName, TcsXmlTaxonImport.unknownSec());
328 }
329 result.setTitleCache(title);
330 }
331 }else{
332 logger.warn("External link types for synonym not yet implemented");
333 }
334 }
335 return result;
336 }
337
338
339
340
341
342 private boolean relationExists(Taxon taxonTo, Synonym synonym, SynonymRelationshipType synRelType){
343 if (synonym == null){
344 return false;
345 }
346 if (synonym.getRelationType(taxonTo).size() > 0){
347 Set<SynonymRelationshipType> relTypeList = synonym.getRelationType(taxonTo);
348 if (relTypeList.contains(synRelType)){
349 return true;
350 }else{
351 logger.warn("Taxon-Synonym pair has 2 different SynonymRelationships. This is against the rules");
352 return false;
353 }
354 }else{
355 return false;
356 }
357 }
358
359 private boolean makeHomotypicSynonymRelations(Taxon aboutTaxon){
360 TaxonNameBase<?,?> aboutName = aboutTaxon.getName();
361 if (aboutName != null){
362 Set<TaxonNameBase> typifiedNames = aboutName.getHomotypicalGroup().getTypifiedNames();
363 for (TaxonNameBase<?,?> typifiedName : typifiedNames){
364 //TODO check if name is part of this tcs file
365 if (typifiedName.equals(aboutName)){
366 continue;
367 }
368 Set<Synonym> syns = typifiedName.getSynonyms();
369 for(Synonym syn:syns){
370 aboutTaxon.addSynonym(syn, SynonymRelationshipType.HOMOTYPIC_SYNONYM_OF());
371 }
372 }
373 }
374 return true;
375 }
376
377 /* (non-Javadoc)
378 * @see eu.etaxonomy.cdm.io.common.CdmIoBase#isIgnore(eu.etaxonomy.cdm.io.common.IImportConfigurator)
379 */
380 protected boolean isIgnore(TcsXmlImportState state){
381 return ! state.getConfig().isDoRelTaxa();
382 }
383
384 }