Package com.hp.hpl.squirrelrdf.rdb

Source Code of com.hp.hpl.squirrelrdf.rdb.RDF2SQLConfig

/*
* (c) Copyright 2006 Hewlett-Packard Development Company, LP
* All rights reserved.
* [See end of file]
*/

package com.hp.hpl.squirrelrdf.rdb;


import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.squirrelrdf.querymap.exceptions.ConfigException;
import com.hp.hpl.squirrelrdf.querymap.exceptions.InconsistentException;
import com.hp.hpl.squirrelrdf.querymap.exceptions.UnanswerableException;

/**
*
* RDF2SQLConfig
*
* Represents a map from RDF (properties, classes, resources) to
* SQL (tables, columns, rows).
*
* @author Damian Steer <pldms@mac.com>
*
*/

public class RDF2SQLConfig
{
  final static Log log = LogFactory.getLog(RDF2SQLConfig.class);
 
  private Model configModel;
  private Resource map;
  private Map<Resource,Col> prop2col;
  private Map<Resource,Database> res2db;
  private Map<Resource,Table> class2table;
 
  /**
   * Initialise an RDF2SQL map from a configuration model.
   *
   * @param configModel The RDF to SQL map configuration.
   * @throws ConfigException  If the configuration doesn't work.
   */
 
  public RDF2SQLConfig(Model configModel) throws ConfigException
  {
    this.configModel = configModel;
    this.prop2col = new HashMap<Resource,Col>();
    this.res2db = new HashMap<Resource,Database>();
    this.class2table = new HashMap<Resource,Table>();
   
    initFromConfigModel();
  }
   
  /**
   * Initialise from config model. Generates the Col, Table, Database representation.
   * @throws ConfigException
   */
  private void initFromConfigModel() throws ConfigException
  {
    ResIterator ri = configModel.listSubjectsWithProperty(RDF.type, DbMap.Map);
   
    if (!ri.hasNext())
      throw new ConfigException("No map in config file");
   
    this.map = ri.nextResource();
    if (ri.hasNext())
      log.warn("There is more than one map in the config file");
   
    StmtIterator si = map.listProperties(DbMap.mapsClass);
    while (si.hasNext())
    {
      Resource aClass = si.nextStatement().getResource();
      initFromClass(aClass);
   
    si.close();
    si = configModel.listStatements(null, DbMap.foreignKey, (RDFNode) null);
    while (si.hasNext())
    {
      Statement s = si.nextStatement();
      Col subj = prop2col.get(s.getSubject());
      Col obj = prop2col.get(s.getObject());
      if (subj == null || obj == null)
        log.warn("Foreign key missed: " + s);
      subj.setForeignKey(obj);
    }
  }
 
  /**
   * Create a table and cols for an rdf class
   * @param aClass
   * @throws ConfigException
   */
  private void initFromClass(Resource aClass) throws ConfigException
  {
    if (class2table.containsKey(aClass)) return; // already done
   
    Resource db = aClass.getProperty(DbMap.database).getResource();
   
    Database database = getDatabase(db);
       
    Table table = new Table(aClass, database);
    class2table.put(aClass, table);
    ResIterator ri = aClass.getModel().listSubjectsWithProperty(RDFS.domain, aClass);
    while (ri.hasNext())
    {
      Resource prop = ri.nextResource();
      Col col = new Col(prop, table);
      prop2col.put(prop, col);
    }
    StmtIterator si = aClass.listProperties(DbMap.primaryKey);
    while (si.hasNext())
    {
      Resource primKey = si.nextStatement().getResource();
      Col primCol = prop2col.get(primKey);
      if (primCol == null)
        throw new ConfigException("Primary key unknown: " + primKey);
      else
        primCol.setIsPrimaryKey(true);
    }
  }
 
  /**
   * Create a database from a config resource
   * @param db
   * @return
   */
  private Database getDatabase(Resource db)
  {
    if (res2db.containsKey(db))
      return res2db.get(db);
   
    Literal user = db.getProperty(DbMap.user).getLiteral();
    Literal pass = db.getProperty(DbMap.pass).getLiteral();
    Literal driver = db.getProperty(DbMap.driver).getLiteral();
    Database database = new Database(db, user, pass, driver);
    res2db.put(db, database); // don't keep creating !!

    return database;
  }
 
  /**
   * Preprocess a query pattern.
   *
   * We can eliminate quite a few queries at this point, simply because
   * they can't be answered.
   *
   * @param triples A query pattern
   * @return A query, ready to execute.
   * @throws InconsistentException If the query can't be answered by this map, ever.
   * @throws UnanswerableException If the query can't be answered due to some limitation of the map.
   */
 
  public ProcessedQuery createQuery(List<Triple> triples) throws InconsistentException, UnanswerableException
  {
    ProcessedQuery query = preprocessTriples(triples);
    return query;
  }

  private ProcessedQuery preprocessTriples(List<Triple> triples) throws InconsistentException, UnanswerableException
  {
    ProcessedQuery query = new ProcessedQuery();
    Map<Node,Resource> nodeToClass = new HashMap<Node,Resource>(); // for sanity checking
   
    for (Triple triple: triples)
    {
      Node subject = triple.getSubject();
      Node predicate = triple.getPredicate();
      Node object = triple.getObject();
     
      if (predicate.isVariable())
        throw new UnanswerableException("I can't do predicate matches (yet).");
     
      if (predicate.equals(RDF.Nodes.type)) // RDB map is staticly typed, so this is not that useful
      {
        if (object.isConcrete())
        {
          Resource theClass = (Resource) configModel.asRDFNode(object);
          Table table = class2table.get(theClass);
          if (table == null)
            throw new InconsistentException("Unknown class: " + object);
          checkClasses(subject, theClass, nodeToClass);
          nodeToClass.put(subject, theClass);
          query.add(subject, table); // Just add the subject and table to the query.
        }
        else
          throw new UnanswerableException("No type matches (yet)");
        continue;
      }
     
      Resource prop = (Resource) configModel.getRDFNode(predicate);
      if (!prop2col.containsKey(prop))
        throw new InconsistentException("Unknown predicate: " + triple);

      /* Domain / Range checks -- subjects have types specific to tables, objects are literals */
      checkClasses(subject, prop.getProperty(RDFS.domain).getResource(), nodeToClass);
      checkClasses(object, RDFS.Literal, nodeToClass);
     
      //if (subject.isConcrete())
      //  throw new UnanswerableException("Concrete subject given: " + triple);
     
      if (object.isConcrete() && !object.isLiteral())
        throw new UnanswerableException("Object is resource: " + triple);
     
      // Ok, that's all the problem cases out the way (well, mostly)
      Col col = prop2col.get(prop);
     
      // Cleaning: bnodes -> =var or #var. That will hurt.
     
      subject = clean(subject);
      object = clean(object);
     
      query.add(subject, col, object);
    }
   
    return query;
  }
 
  /*
   * Clean nodes. Bnodes in sparql become (rather funky) variables, whose names need fixing
   */
  private Node clean(Node node)
  {
    if (!node.isVariable()) return node;
    if (node.getName().startsWith("="))
      return Node.createVariable(node.getName().replaceFirst("=","bnode\\$"));
    if (node.getName().startsWith("#"))
      return Node.createVariable(node.getName().replaceFirst("#","bnode\\$"));
    return node;
  }
 
  /* domain / range checking */
  private void checkClasses(Node node, Resource aClass, Map<Node,Resource> nodeToClass)
    throws InconsistentException
  {
    if (!nodeToClass.containsKey(node))
    {
      nodeToClass.put(node, aClass);
      return;
    }
   
    Resource existingClass = (Resource) nodeToClass.get(node);
    if (!existingClass.equals(aClass))
      throw new InconsistentException("Inconsistent classes for " + node +
          ": both " + existingClass + " and " + aClass);
  }
 
 
  /**
   * Close all existing database connections
   *
   * @throws SQLException
   */
  public void close() throws SQLException
  {
    for (Database db: res2db.values())
    {
      db.closeConnection();
    }
  }
}

/*
* (c) Copyright 2006 Hewlett-Packard Development Company, LP
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
*    derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ 
TOP

Related Classes of com.hp.hpl.squirrelrdf.rdb.RDF2SQLConfig

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.