1 5 6 package org.joseki.server; 7 8 import java.util.* ; 9 import org.apache.commons.logging.* ; 10 11 import org.joseki.* ; 12 import org.joseki.util.* ; 13 import org.joseki.server.source.* ; 14 import org.joseki.vocabulary.*; 15 import org.joseki.server.module.*; 16 17 import com.hp.hpl.jena.rdf.model.* ; 18 19 import com.hp.hpl.jena.ontology.* ; 20 import com.hp.hpl.jena.shared.* ; 21 import com.hp.hpl.jena.vocabulary.* ; 22 25 26 32 33 34 public class Configuration 35 { 36 private static Log log = LogFactory.getLog(Configuration.class.getName()); 37 38 public static final String oldNS[] = {"http://joseki.org/2002/06/configuration#"} ; 40 41 Model configurationModel = ModelFactory.createDefaultModel() ; 42 ClassLoader classLoader = null ; 43 Loader moduleLoader = new Loader() ; 44 FileManager fileManager = FileManager.getInstance() ; 45 46 47 public Configuration() 48 { 49 classLoader = chooseClassLoader() ; 50 } 51 52 public Model getConfigurationModel() { return configurationModel ; } 53 54 56 public void load(ModelSet modelSet, String configFile) 57 { 58 log.info("Load configuration: "+configFile) ; 59 60 Set filesRead = new HashSet() ; 61 62 readConfFile(configurationModel, configFile, filesRead) ; 63 64 processConfigurationModel(modelSet) ; 65 } 66 67 private void readConfFile(Model confModel, String fileName, Set filesDone) 68 { 69 try 70 { 71 75 Model m = ModelFactory.createDefaultModel() ; 76 m = fileManager.readModel(m, fileName) ; 77 if ( m == null ) 78 { 79 log.warn("No configuration model: "+fileName) ; 80 throw new ConfigurationErrorException("Configuration file not found: "+fileName) ; 81 } 83 84 log.info("Read: "+fileName) ; 85 filesDone.add(fileName) ; 86 87 Set filesToDo = new HashSet() ; 88 89 ResIterator rIter = m.listSubjectsWithProperty(RDF.type, JosekiVocab.JosekiServer) ; 90 for ( ; rIter.hasNext() ; ) 91 { 92 Resource r = rIter.nextResource() ; 93 StmtIterator sIter = r.listProperties(JosekiVocab.alsoInclude) ; 94 for ( ; sIter.hasNext() ; ) 95 { 96 Resource fileName2 = sIter.nextStatement().getResource() ; 97 if ( fileName2.isAnon() ) 98 continue ; 99 String fullname = fileName2.getURI() ; 100 if ( ! filesDone.contains(fullname) ) 101 filesToDo.add(fullname) ; 102 } 103 sIter.close() ; 104 } 105 rIter.close() ; 106 confModel.add(m) ; 107 for ( Iterator iter = filesToDo.iterator() ; iter.hasNext() ; ) 108 { 109 readConfFile(confModel, (String )iter.next(), filesDone) ; 110 } 111 112 } catch (RDFException rdfEx) 113 { 114 log.warn(fileName+": RDF Exception: "+rdfEx.getMessage()) ; 115 throw new ConfigurationErrorException("RDF Exception: "+rdfEx.getMessage(), rdfEx) ; 116 } 118 } 119 120 123 private void processConfigurationModel(ModelSet modelSet) 124 { 125 127 NsIterator nsIter = configurationModel.listNameSpaces() ; 128 for ( ; nsIter.hasNext() ;) 129 { 130 String ns = nsIter.nextNs() ; 131 for ( int i = 0 ; i < oldNS.length ; i++) 132 { 133 if ( oldNS[i].equals(ns) ) 134 { 135 log.error("Found out of date configuration information found") ; 136 log.error(" Configuration URI for this codebase is "+JosekiVocab.NS) ; 137 throw new ConfigurationErrorException("Out of date configuration information") ; 138 } 139 } 140 } 141 processServerConfiguration() ; 143 144 processSources(modelSet) ; 145 } 146 147 148 private void processServerConfiguration() 149 { 150 try 151 { 152 log.trace("Start server configuration") ; 153 ResIterator rIter = configurationModel.listSubjectsWithProperty(RDF.type, JosekiVocab.JosekiServer) ; 155 for ( ; rIter.hasNext() ; ) 156 { 157 Resource r = rIter.nextResource() ; 158 159 if ( r.hasProperty(JosekiVocab.serverDebug) ) 160 { 161 Joseki.serverDebug = 162 r.getRequiredProperty(JosekiVocab.serverDebug).getString().equals("true") ; 163 } 164 165 if ( r.hasProperty(JosekiVocab.useContentType) ) 166 { 167 String contentType = r.getRequiredProperty(JosekiVocab.useContentType).getString() ; 168 169 if ( contentType.equals(Joseki.contentTypeN3) || 170 contentType.equals(Joseki.contentTypeRDFXML) || 171 contentType.equals(Joseki.contentTypeNTriples) ) 172 { 173 log.debug("Content type: "+contentType) ; 174 Joseki.serverContentType = contentType ; 175 } 176 else 177 { 178 log.warn("Unknown content-type: "+contentType) ; 179 } 180 } 181 182 Property oldFeature = r.getModel().createProperty(JosekiVocab.NS, "loadJavaClass") ; 183 if ( r.hasProperty(oldFeature) ) 184 log.warn("Old style 'joseki:javaLoadClass' found : use joseki:dbDriver on attached model") ; 185 } 186 rIter.close(); 187 188 } catch (RDFException rdfEx) 189 { 190 log.warn("Error in configuration file (server section)", rdfEx) ; 191 throw new ConfigurationErrorException("Error in configuration file (server section)", rdfEx) ; 192 } 193 194 if ( Joseki.serverDebug ) 195 log.info("Server debug on") ; 196 197 log.trace("Finish server configuration") ; 198 } 199 200 201 private void processSources(ModelSet modelSet) 202 { 203 String loggingIndicator = "<<unset>>" ; 204 try 205 { 206 ResIterator rIter = 208 configurationModel.listSubjectsWithProperty(JosekiVocab.attachedModel); 209 if ( ! rIter.hasNext() ) 210 log.warn("No models to attach") ; 211 212 for (; rIter.hasNext();) 213 { 214 Resource modelSource = rIter.nextResource(); 215 if ( modelSource.isAnon() ) 216 { 217 log.warn("Attached model is a bNode - need a URI") ; 218 continue ; 219 } 220 String serverURI = ModelSet.resource2serverURI(modelSource) ; 221 222 loggingIndicator = serverURI ; 223 ModelSource srcModel = null ; 224 try { 225 srcModel = processModel(modelSource, serverURI) ; 226 } catch (JenaException ex) 227 { 228 log.warn("Error in configuration file. Model:"+loggingIndicator) ; 229 ex.printStackTrace(System.out) ; 230 continue ; 231 } 232 if ( srcModel == null ) 233 continue ; 234 modelSet.addModel(serverURI, srcModel) ; 235 } 236 rIter.close() ; 237 } 238 catch (RDFException rdfEx) 239 { 240 log.warn("Error in configuration file (model section): "+loggingIndicator) ; 241 throw new ConfigurationErrorException("Error in configuration file (model section): "+loggingIndicator) ; 242 } 243 } 244 245 246 private ModelSource processModel(Resource modelSource, String serverURI) 247 { 248 if ( modelSource.isAnon() ) 249 { 250 log.warn("Anonymous node for external resource!") ; 251 return null ; 252 } 253 254 Statement sourceStmt = modelSource.getProperty(JosekiVocab.attachedModel) ; 255 if ( sourceStmt == null ) 256 { 257 log.warn("Model: "+serverURI + " : No internal Jena model specified") ; 258 return null ; 259 } 260 261 String internalURI = null ; 262 try { 263 internalURI = sourceStmt.getResource().getURI() ; 264 log.info("Model: "+serverURI + " ==> " + internalURI) ; 265 } catch (RDFException ex) 266 { 267 log.warn("No internal resource URI for "+serverURI) ; 268 return null ; 269 } 270 271 ModelSource src = buildModelSource(modelSource, internalURI, serverURI) ; 272 273 if ( src == null ) 274 { 275 log.warn("Failed to attach "+internalURI) ; 276 return null ; 277 } 278 279 log.trace("Base model built") ; 280 281 if ( modelSource.hasProperty(JosekiVocab.modelSpec) ) 282 { 283 log.warn("Description by ModelSpec: Not implemented (yet)") ; 284 return null ; 285 } 286 else 287 { 288 if ( modelSource.hasProperty(JosekiVocab.vocabulary) || 289 modelSource.hasProperty(JosekiVocab.ontology) ) 290 { 291 src = buildOntModelSource(modelSource, serverURI, src) ; 292 if ( src == null ) 293 return null ; 295 } 296 } 297 298 if ( modelSource.hasProperty(JosekiVocab.isImmutable) ) 299 { 300 String tmp = modelSource.getProperty(JosekiVocab.isImmutable).getString() ; 301 if ( tmp.equalsIgnoreCase("true") ) 302 { 303 log.debug(" Immutable model") ; 304 src.setIsImmutable(true) ; 305 } 306 } 307 308 buildQueryProcs(modelSource, src) ; 310 buildOtherProcs(modelSource, src) ; 311 312 assignNamespaces(modelSource, src) ; 313 return src ; 314 } 315 316 317 318 private ModelSource buildOntModelSource(Resource modelSource, String serverURI, ModelSource src) 320 { 321 final boolean hasRDFS = modelSource.hasProperty(JosekiVocab.vocabulary) ; 322 final boolean hasOWL = modelSource.hasProperty(JosekiVocab.ontology) ; 323 324 if ( ! hasRDFS && ! hasOWL ) 325 return src ; 326 327 if ( hasRDFS && hasOWL ) 328 { 329 log.warn("Can't have both an OWL ontology and an RDFS vocabulary") ; 330 return null ; 331 } 332 333 if ( ! (src instanceof ModelSourceJena) ) 334 { 335 log.warn("Jena inference subsystem only works with Jena models") ; 336 return null ; 337 } 338 339 Model aBox = ((ModelSourceJena)src).getModel() ; 340 Model newModel = null ; 341 342 if ( hasRDFS ) 343 { 344 Resource vocabulary = modelSource 345 .getProperty(JosekiVocab.vocabulary) 346 .getResource() ; 347 log.info(" Applying RDFS: "+vocabulary) ; 348 349 Model vocabularyModel = fileManager.loadModel(vocabulary.getURI()) ; 350 newModel = ModelFactory.createRDFSModel(vocabularyModel, aBox) ; 351 } 352 353 if ( hasOWL ) 354 { 355 Resource ontology = modelSource.getProperty(JosekiVocab.vocabulary) 356 .getResource() ; 357 Model tBox = fileManager.loadModel(ontology.getURI()) ; 358 log.info(" Applying OWL: "+ontology) ; 359 360 Model ontDocMgr = null ; 361 if ( modelSource.hasProperty(JosekiVocab.ontDocumentManager)) 362 { 363 Resource r = modelSource.getProperty(JosekiVocab.ontDocumentManager).getResource() ; 364 String ontDocMgrURI = r.getURI() ; 365 log.info(" Ontology document manager: "+ontDocMgrURI) ; 366 ontDocMgr = fileManager.loadModel(ontDocMgrURI) ; 367 } 368 369 OntModelSpec s = new OntModelSpec( OntModelSpec.OWL_LITE_MEM_RULES_INF ); 370 if ( ontDocMgr != null ) 371 s.setDocumentManager( new OntDocumentManager(ontDocMgr)) ; 372 s.getReasoner().bindSchema(tBox) ; 373 newModel = ModelFactory.createOntologyModel( s, aBox ); 374 } 375 376 newModel.setNsPrefixes(aBox) ; 377 SourceController sCtl = new SourceControllerPermanent(newModel) ; 379 src = sCtl.createSourceModel(null, serverURI) ; 380 return src ; 381 } 382 383 private ModelSource buildModelSource(Resource sourceDesc, String modelURI, String serverURI) 384 { 385 Resource module = null ; 386 387 if ( sourceDesc.hasProperty(JosekiVocab.sourceController) ) 388 { 389 module = sourceDesc.getProperty(JosekiVocab.sourceController).getResource() ; 390 log.debug(" Custom source controller: "+PrintUtils.fmt(module)) ; 391 } 392 else 393 { 394 396 if ( modelURI.toLowerCase().startsWith("file:") ) 397 { 398 log.trace(" File source") ; 399 module = sourceDesc.getModel().getResource(JosekiVocab.sourceControllerFile) ; 400 } 401 402 if ( modelURI.toLowerCase().startsWith("jdbc:") ) 403 { 404 log.trace(" JDBC source") ; 405 module = sourceDesc.getModel().getResource(JosekiVocab.sourceControllerRDB) ; 406 } 407 } 408 409 if ( module == null ) 410 { 411 log.warn("Can't find module for source controller for "+serverURI+" : not named, not a file and not a database") ; 412 return null ; 413 } 414 415 SourceController srcCtl = (SourceController)moduleLoader.loadAndInstantiate(module, SourceController.class) ; 416 417 if ( srcCtl == null ) 418 { 419 log.warn("Can't load find source controller for "+serverURI) ; 420 return null ; 421 } 422 423 ModelSource a = srcCtl.createSourceModel(sourceDesc, serverURI) ; 424 log.trace("Built model source controller") ; 425 return a ; 426 } 427 428 private void buildQueryProcs(Resource modelSource, ModelSource src) 430 { 431 StmtIterator queryBindings = modelSource.listProperties(JosekiVocab.hasQueryOperation); 432 for (; queryBindings.hasNext();) 433 { 434 Resource binding = queryBindings.nextStatement().getResource(); 435 QueryProcessor qProc = (QueryProcessor)moduleLoader.loadAndInstantiate(binding, QueryProcessor.class) ; 436 437 if ( qProc == null ) 438 continue ; 439 440 StmtIterator langNameIter = binding.listProperties(JosekiVocab.queryOperationName); 443 for (; langNameIter.hasNext();) 444 { 445 Statement s = langNameIter.nextStatement(); 446 String langName = null ; 447 if ( s.getObject() instanceof Literal ) 448 langName = s.getString(); 449 else 450 { 451 if ( s.getResource().isAnon() ) 452 { 453 log.warn("Query langauge name must be a literal or a URI") ; 454 continue ; 455 } 456 langName = s.getResource().getURI() ; 457 } 458 log.info(" Query Language: " + langName); 459 if ( src.getProcessorRegistry().hasQueryProcessor(langName) ) 460 log.warn(" Query language '"+langName+"' already assigned") ; 461 src.getProcessorRegistry().registerQueryProcessor(langName, qProc); 462 } 463 langNameIter.close() ; 464 } 465 } 466 467 private void buildOtherProcs(Resource modelSource, ModelSource src) 469 { 470 StmtIterator operationBindings = modelSource.listProperties(JosekiVocab.hasOperation); 471 for (; operationBindings.hasNext();) 472 { 473 Resource binding = operationBindings.nextStatement().getResource(); 474 Processor proc = (Processor)moduleLoader.loadAndInstantiate(binding, Processor.class) ; 475 476 if (proc == null) 477 continue; 478 479 StmtIterator opNameIter = binding.listProperties(JosekiVocab.operationName) ; 480 for ( ; opNameIter.hasNext() ;) 481 { 482 Statement s = opNameIter.nextStatement(); 483 if ( s.getPredicate().equals(JosekiVocab.queryOperationName)) 484 continue ; 485 String opName = null ; 486 if ( s.getObject() instanceof Literal ) 487 opName = s.getString(); 488 else 489 { 490 if ( s.getResource().isAnon() ) 491 { 492 log.warn("Operation name must be a literal or a URI") ; 493 continue ; 494 } 495 opName = s.getResource().getURI() ; 496 } 497 log.info(" Operation: " + opName); 498 if ( src.getProcessorRegistry().hasProcessor(opName) ) 499 log.warn(" Operation '"+opName+"' already assigned") ; 500 501 src.getProcessorRegistry().registerProcessor(opName, proc); 502 } 503 opNameIter.close() ; 504 } 505 } 506 507 508 private void assignNamespaces(Resource modelSource, ModelSource src) 509 { 510 StmtIterator prefixIter = modelSource.listProperties(JosekiVocab.namespacePrefix); 512 for (; prefixIter.hasNext();) 513 { 514 Statement s = prefixIter.nextStatement(); 515 if (!(s.getObject() instanceof Resource)) 516 { 517 log.warn("Error in configuration file: " + modelSource + " has non-resource namespace prefix"); 518 break; 519 } 520 try 521 { 522 String prefix = s.getResource().getRequiredProperty(JosekiVocab.prefix).getString(); 523 String nsURI = s.getResource().getRequiredProperty(JosekiVocab.nsURI).getResource().getURI(); 524 log.debug(" Namespace: " + prefix + " <=> " + nsURI); 525 src.setPrefix(prefix, nsURI); 526 } 527 catch (RDFException rdfEx) 528 { 529 log.warn("Error in configuration file: " + modelSource + " has ill-formed prefix declaration"); 530 break; 531 } 532 } 533 } 534 535 private ClassLoader chooseClassLoader() 536 { 537 ClassLoader classLoader = null ; 538 539 if ( classLoader == null ) 540 { 541 classLoader = Thread.currentThread().getContextClassLoader(); 543 if ( classLoader != null ) 544 log.trace("Using thread classloader") ; 545 } 546 547 if (classLoader == null) 548 { 549 classLoader = this.getClass().getClassLoader(); 550 if ( classLoader != null ) 551 log.trace("Using 'this' classloader") ; 552 } 553 554 if ( classLoader == null ) 555 { 556 classLoader = ClassLoader.getSystemClassLoader() ; 557 if ( classLoader != null ) 558 log.trace("Using system classloader") ; 559 } 560 561 if ( classLoader == null ) 562 log.warn("Failed to find a classloader") ; 563 return classLoader ; 564 } 565 566 } 577 578 604 | Popular Tags |