001 /** 002 * OntologyConnector.java 003 * jCOLIBRI2 framework. 004 * @author Juan A. Recio-García. 005 * GAIA - Group for Artificial Intelligence Applications 006 * http://gaia.fdi.ucm.es 007 * 07/06/2007 008 */ 009 package jcolibri.connector; 010 011 import java.io.FileWriter; 012 import java.net.URL; 013 import java.util.ArrayList; 014 import java.util.Collection; 015 import java.util.Iterator; 016 017 import javax.xml.parsers.DocumentBuilder; 018 import javax.xml.parsers.DocumentBuilderFactory; 019 020 import jcolibri.cbrcore.Attribute; 021 import jcolibri.cbrcore.CBRCase; 022 import jcolibri.cbrcore.CaseBaseFilter; 023 import jcolibri.cbrcore.CaseComponent; 024 import jcolibri.cbrcore.Connector; 025 import jcolibri.connector.ontologyutils.OntologyInfo; 026 import jcolibri.connector.ontologyutils.OntologyMapping; 027 import jcolibri.datatypes.Instance; 028 import jcolibri.exception.InitializingException; 029 import jcolibri.util.FileIO; 030 import jcolibri.util.ProgressController; 031 032 import org.w3c.dom.Document; 033 import org.w3c.dom.Node; 034 import org.w3c.dom.NodeList; 035 036 import es.ucm.fdi.gaia.ontobridge.OntoBridge; 037 import es.ucm.fdi.gaia.ontobridge.OntologyDocument; 038 039 /** 040 * Implements a generic Ontology connector. 041 * It uses OntoBridge to manage the ontologies and the reasoner. 042 * To configure this connector create a configuration xml file following this schema: 043 * <a href="OntologyConnector.xsd">/doc/configfilesSchemas/OntologyConnector.xsd</a>:<p> 044 * <img src="OntologyConnectorSchema.jpg"> 045 * <p> 046 * This connector only maps case structures without compound attributes. 047 * All attributes must be Instance typed. 048 * 049 * For a complete example see Test 10. 050 * 051 * @author Juan A. Recio-Garcia 052 * @version 2.0 053 * @see jcolibri.test.test10.Test10 054 */ 055 public class OntologyConnector implements Connector { 056 057 private Class descriptionClass; 058 private Class solutionClass; 059 private Class justOfSolutionClass; 060 private Class resultClass; 061 062 private OntologyInfo mainOntologyInfo; 063 private ArrayList<OntologyInfo> subOntologiesInfo; 064 065 private String CaseMainConcept; 066 067 private ArrayList<OntologyMapping> descriptionMappings; 068 private ArrayList<OntologyMapping> solutionMappings; 069 private ArrayList<OntologyMapping> justOfSolutionMappings; 070 private ArrayList<OntologyMapping> resultMappings; 071 072 private boolean modified; 073 074 private OntologyInfo getOntologyInfo(Node node) 075 { 076 OntologyInfo oi = new OntologyInfo(); 077 NodeList ontologyNodes = node.getChildNodes(); 078 for(int i=0; i<ontologyNodes.getLength(); i++) 079 { 080 Node n = ontologyNodes.item(i); 081 if(n.getNodeName().equals("URL")) 082 oi.setUrl(n.getTextContent()); 083 else if(n.getNodeName().equals("LocalCopy")) 084 oi.setLocalCopy(n.getTextContent()); 085 } 086 return oi; 087 } 088 089 private void getOntologyMappings(Node mappings, ArrayList<OntologyMapping> descriptionMappings) { 090 NodeList mappingNodes = mappings.getChildNodes(); 091 for(int i=0; i<mappingNodes.getLength(); i++) 092 { 093 Node n = mappingNodes.item(i); 094 if(!n.getNodeName().equals("Map")) 095 continue; 096 OntologyMapping om = new OntologyMapping(); 097 NodeList contents = n.getChildNodes(); 098 for(int j=0; j<contents.getLength(); j++) 099 { 100 Node c = contents.item(j); 101 if(c.getNodeName().equals("Property")) 102 om.setProperty(c.getTextContent()); 103 else if(c.getNodeName().equals("Concept")) 104 om.setConcept(c.getTextContent()); 105 else if(c.getNodeName().equals("Attribute")) 106 om.setAttribute(c.getTextContent()); 107 } 108 descriptionMappings.add(om); 109 } 110 } 111 112 /** 113 * Initializes the connector from an XML config file. 114 * This method reads the configuration and launches OntoBridge with the Pellet reasoner. 115 * Then the ontologies are loaded into memory. 116 * 117 * @see jcolibri.cbrcore.Connector#initFromXMLfile(java.net.URL) 118 */ 119 public void initFromXMLfile(URL file) throws InitializingException { 120 121 122 try { 123 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 124 DocumentBuilder db = dbf.newDocumentBuilder(); 125 Document doc = db.parse(file.openStream()); 126 127 /* Main Ontology Info */ 128 mainOntologyInfo = getOntologyInfo(doc.getElementsByTagName("MainOntology").item(0)); 129 130 /* SubOntologies Info */ 131 subOntologiesInfo = new ArrayList<OntologyInfo>(); 132 NodeList subOntologiesNodes = doc.getElementsByTagName("SubOntology"); 133 for(int i=0; i<subOntologiesNodes.getLength(); i++) 134 subOntologiesInfo.add(getOntologyInfo(subOntologiesNodes.item(i))); 135 136 /* Case Main Concept */ 137 this.CaseMainConcept = doc.getElementsByTagName("CaseMainConcept").item(0).getTextContent(); 138 139 140 /* Description mapping */ 141 this.descriptionClass = Class.forName(doc.getElementsByTagName("DescriptionClassName").item(0).getTextContent()); 142 Node mappings = doc.getElementsByTagName("DescriptionMappings").item(0); 143 this.descriptionMappings = new ArrayList<OntologyMapping>(); 144 getOntologyMappings(mappings, descriptionMappings); 145 146 /* Solution mapping */ 147 try{ 148 this.solutionClass = Class.forName(doc.getElementsByTagName("SolutionClassName").item(0).getTextContent()); 149 mappings = doc.getElementsByTagName("SolutionMappings").item(0); 150 this.solutionMappings = new ArrayList<OntologyMapping>(); 151 getOntologyMappings(mappings, solutionMappings); 152 }catch(Exception e) {} 153 154 /* JustOfSolution mapping */ 155 try{ 156 this.justOfSolutionClass = Class.forName(doc.getElementsByTagName("JustificationOfSolutionClassName").item(0).getTextContent()); 157 mappings = doc.getElementsByTagName("JustificationOfSolutionMappings").item(0); 158 this.justOfSolutionMappings = new ArrayList<OntologyMapping>(); 159 getOntologyMappings(mappings, justOfSolutionMappings); 160 }catch(Exception e) {} 161 162 /* result mapping */ 163 try{ 164 this.resultClass = Class.forName(doc.getElementsByTagName("ResultClassName").item(0).getTextContent()); 165 mappings = doc.getElementsByTagName("ResultMappings").item(0); 166 this.resultMappings = new ArrayList<OntologyMapping>(); 167 getOntologyMappings(mappings, resultMappings); 168 }catch(Exception e) {} 169 170 171 // Now let's initialize Ontobridge 172 173 // Obtain a reference to OntoBridge 174 OntoBridge ob = jcolibri.util.OntoBridgeSingleton.getOntoBridge(); 175 // Configure it to work with the Pellet reasoner 176 ob.initWithPelletReasoner(); 177 // Setup the main ontology 178 OntologyDocument mainOnto = new OntologyDocument(this.mainOntologyInfo.getUrl(), 179 FileIO.findFile(this.mainOntologyInfo.getLocalCopy()).toExternalForm()); 180 // Setup subontologies 181 ArrayList<OntologyDocument> subOntologies = new ArrayList<OntologyDocument>(); 182 for(OntologyInfo oi : this.subOntologiesInfo) 183 { 184 OntologyDocument subOnto = new OntologyDocument(oi.getUrl(), 185 FileIO.findFile(oi.getLocalCopy()).toURI().toString()); 186 subOntologies.add(subOnto); 187 } 188 189 // Load the ontology 190 ob.loadOntology(mainOnto, subOntologies, false); 191 192 // Set modified to false 193 this.modified = false; 194 195 } catch (Exception e) { 196 throw new InitializingException(e); 197 } 198 199 200 } 201 202 203 /* (non-Javadoc) 204 * @see jcolibri.cbrcore.Connector#retrieveAllCases() 205 */ 206 public Collection<CBRCase> retrieveAllCases() { 207 208 //Result list 209 ArrayList<CBRCase> cases = new ArrayList<CBRCase>(); 210 211 //Obtain OntoBridge 212 OntoBridge ob = jcolibri.util.OntoBridgeSingleton.getOntoBridge(); 213 214 ProgressController.init(this.getClass(), "Loading concepts", ProgressController.UNKNOWN_STEPS); 215 216 //Obtain instances 217 Iterator<String> caseInstances = ob.listInstances(this.CaseMainConcept); 218 while(caseInstances.hasNext()) 219 { 220 String caseInstance = caseInstances.next(); 221 CBRCase _case = new CBRCase(); 222 223 try { 224 //Map description 225 CaseComponent description = (CaseComponent)this.descriptionClass.newInstance(); 226 retrieveCaseComponent(ob, description, caseInstance, this.descriptionMappings); 227 _case.setDescription(description); 228 229 //Map solution 230 if(this.solutionClass != null) 231 { 232 CaseComponent cc = (CaseComponent)this.solutionClass.newInstance(); 233 retrieveCaseComponent(ob, cc, caseInstance, this.solutionMappings); 234 _case.setSolution(cc); 235 } 236 237 //Map justification of solution 238 if(this.justOfSolutionClass != null) 239 { 240 CaseComponent cc = (CaseComponent)this.justOfSolutionClass.newInstance(); 241 retrieveCaseComponent(ob, cc, caseInstance, this.justOfSolutionMappings); 242 _case.setJustificationOfSolution(cc); 243 } 244 245 //Map result solution 246 if(this.resultClass != null) 247 { 248 CaseComponent cc = (CaseComponent)this.resultClass.newInstance(); 249 retrieveCaseComponent(ob, cc, caseInstance, this.resultMappings); 250 _case.setResult(cc); 251 } 252 253 // If everything ok add the case to the list 254 cases.add(_case); 255 256 } catch (Exception e) { 257 org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e); 258 } 259 260 ProgressController.step(this.getClass()); 261 } 262 ProgressController.finish(this.getClass()); 263 return cases; 264 } 265 266 private void retrieveCaseComponent(OntoBridge ob, CaseComponent cc, String mainInstanceName, ArrayList<OntologyMapping> mappings) throws Exception 267 { 268 //Id 269 Instance id = new Instance(mainInstanceName); 270 cc.getIdAttribute().setValue(cc, id); 271 272 //Other attributes 273 for(OntologyMapping om: mappings) 274 { 275 // Obtain CaseComponent attribute 276 Attribute at = new Attribute(om.getAttribute(), cc.getClass()); 277 278 // Find values of the property. It could have several values. 279 Iterator<String> values = ob.listPropertyValue(mainInstanceName, om.getProperty()); 280 // Find which value is instance of the concept 281 boolean found = false; 282 while(values.hasNext() && !found) 283 { 284 String valueInstance = values.next(); 285 if(ob.isInstanceOf(valueInstance, om.getConcept())) 286 { 287 found = true; 288 Instance concept = new Instance(valueInstance); 289 at.setValue(cc, concept); 290 } 291 } 292 } 293 294 } 295 296 /** 297 * UnImplemented. 298 * @see jcolibri.cbrcore.Connector#retrieveSomeCases(jcolibri.cbrcore.CaseBaseFilter) 299 */ 300 public Collection<CBRCase> retrieveSomeCases(CaseBaseFilter filter) { 301 org.apache.commons.logging.LogFactory.getLog(this.getClass()).error("retrieveSomeCases(CaseBaseFilter) method is not yet implemented"); 302 return null; 303 } 304 305 /** 306 * Stores cases into the ontology. 307 * @see jcolibri.cbrcore.Connector#storeCases(java.util.Collection) 308 */ 309 public void storeCases(Collection<CBRCase> cases) { 310 311 if(cases.isEmpty()) 312 return; 313 else 314 modified = true; 315 316 317 //Obtain OntoBridge 318 OntoBridge ob = jcolibri.util.OntoBridgeSingleton.getOntoBridge(); 319 320 ProgressController.init(this.getClass(), "Storing concepts/cases", cases.size()); 321 for(CBRCase _case: cases) 322 { 323 try { 324 if(!ob.existsInstance(_case.getID().toString(),this.CaseMainConcept)) 325 ob.createInstance(this.CaseMainConcept, _case.getID().toString()); 326 createCaseComponent(_case.getDescription(), this.descriptionMappings); 327 createCaseComponent(_case.getSolution(), this.solutionMappings); 328 createCaseComponent(_case.getJustificationOfSolution(), this.justOfSolutionMappings); 329 createCaseComponent(_case.getResult(), this.resultMappings); 330 } catch (Exception e) { 331 org.apache.commons.logging.LogFactory.getLog(this.getClass()).error("Error storing case: "+_case+". Cause: "+ e.getMessage()); 332 } 333 ProgressController.step(this.getClass()); 334 } 335 ProgressController.finish(this.getClass()); 336 } 337 338 private void createCaseComponent(CaseComponent cc, ArrayList<OntologyMapping> maps) throws Exception 339 { 340 if((cc == null)||(maps==null)) 341 return; 342 343 OntoBridge ob = jcolibri.util.OntoBridgeSingleton.getOntoBridge(); 344 345 String mainInstance = cc.getIdAttribute().getValue(cc).toString(); 346 347 for(OntologyMapping om: maps) 348 { 349 350 Attribute at = new Attribute(om.getAttribute(), cc.getClass()); 351 String instance = at.getValue(cc).toString(); 352 if(!ob.existsInstance(instance,om.getConcept())) 353 ob.createInstance(om.getConcept(), instance); 354 ob.createOntProperty(mainInstance, om.getProperty(), instance); 355 } 356 357 358 } 359 360 /** 361 * If there was any modification to the ontology, the owl file is replaced with a new one that contains the changes. 362 * The new owl file is completely regenerated from scrach with the current content of the reasoner (not including the inferred model). 363 * OntoBridge uses the RDF/XML-ABBREV syntax for the owl files. 364 * 365 * @see jcolibri.cbrcore.Connector#close() 366 */ 367 public void close() { 368 if(!modified) 369 return; 370 OntoBridge ob = jcolibri.util.OntoBridgeSingleton.getOntoBridge(); 371 try { 372 ob.save(new FileWriter(FileIO.findFile(this.mainOntologyInfo.getLocalCopy()).getFile())); 373 } catch (Exception e) { 374 org.apache.commons.logging.LogFactory.getLog(this.getClass()).error(e); 375 } 376 377 } 378 379 /** 380 * Deletes cases in the ontology. Only the main instance (case id mapped instance) is removed, so the instances mapped to attributes are keep. 381 * @see jcolibri.cbrcore.Connector#deleteCases(java.util.Collection) 382 */ 383 public void deleteCases(Collection<CBRCase> cases) { 384 385 if(cases.isEmpty()) 386 return; 387 else 388 modified = true; 389 390 OntoBridge ob = jcolibri.util.OntoBridgeSingleton.getOntoBridge(); 391 392 ProgressController.init(this.getClass(), "Deleting concepts/cases", cases.size()); 393 for(CBRCase _case: cases) 394 { 395 ob.delete(_case.getID().toString()); 396 ProgressController.step(this.getClass()); 397 } 398 ProgressController.finish(this.getClass()); 399 400 } 401 402 403 404 /**************************************************************/ 405 /*********** Public API for the connector configuration */ 406 /**************************************************************/ 407 408 409 /** 410 * @return Returns the caseMainConcept. 411 */ 412 public String getCaseMainConcept() { 413 return CaseMainConcept; 414 } 415 416 /** 417 * @return Returns the descriptionMappings. 418 */ 419 public ArrayList<OntologyMapping> getDescriptionMappings() { 420 return descriptionMappings; 421 } 422 423 /** 424 * @return Returns the justOfSolutionMappings. 425 */ 426 public ArrayList<OntologyMapping> getJustOfSolutionMappings() { 427 return justOfSolutionMappings; 428 } 429 430 /** 431 * @return Returns the mainOntologyInfo. 432 */ 433 public OntologyInfo getMainOntologyInfo() { 434 return mainOntologyInfo; 435 } 436 437 /** 438 * @return Returns the resultMappings. 439 */ 440 public ArrayList<OntologyMapping> getResultMappings() { 441 return resultMappings; 442 } 443 444 /** 445 * @return Returns the solutionMappings. 446 */ 447 public ArrayList<OntologyMapping> getSolutionMappings() { 448 return solutionMappings; 449 } 450 451 /** 452 * @return Returns the subOntologiesInfo. 453 */ 454 public ArrayList<OntologyInfo> getSubOntologiesInfo() { 455 return subOntologiesInfo; 456 } 457 458 459 460 }