Coverage Report - us.daveread.basicquery.util.RdbToRdf
 
Classes in this File Line Coverage Branch Coverage Complexity
RdbToRdf
0%
0/192
0%
0/24
0
 
 1  
 package us.daveread.basicquery.util;
 2  
 
 3  
 /**
 4  
  * RdbToRdf - A proof-of-concept (POC) for converting relational
 5  
  * data into RDF triples using inferencing
 6  
  * 
 7  
  * This program uses Jena and Pellet to allow for the creation of
 8  
  * a set of RDF triples based on data from a relational database
 9  
  * query.
 10  
  * 
 11  
  * NOTE: THIS PROGRAM IS SOLELY FOR USE AS A PROOF-OF-CONCEPT.  IT
 12  
  * PLACES A DATABASE PASSWORD IN PLAINTEXT WITHIN A CONFIGURATION
 13  
  * FILE.  THIS IS AN INSECURE PRACTICE THAT SHOULD NOT BE USED FOR
 14  
  * AN APPLICATION THAT ACCESSES PRODUCTION DATA.
 15  
  * 
 16  
  *    Copyright (C) 2010 David S. Read
 17  
  *
 18  
  *    This program is free software: you can redistribute it and/or modify
 19  
  *    it under the terms of the GNU Affero General Public License as
 20  
  *    published by the Free Software Foundation, either version 3 of the
 21  
  *    License, or (at your option) any later version.
 22  
  *
 23  
  *    This program is distributed in the hope that it will be useful,
 24  
  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 25  
  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 26  
  *    GNU Affero General Public License for more details.
 27  
  *
 28  
  *    You should have received a copy of the GNU Affero General Public License
 29  
  *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 30  
  *    
 31  
  *    For information on Jena: http://jena.sourceforge.net/
 32  
  *    For information on Pellet: http://clarkparsia.com/pellet
 33  
  */
 34  
 
 35  
 import java.io.FileWriter;
 36  
 import java.io.IOException;
 37  
 import java.sql.ResultSet;
 38  
 import java.sql.ResultSetMetaData;
 39  
 import java.sql.SQLException;
 40  
 import java.sql.Types;
 41  
 import java.text.SimpleDateFormat;
 42  
 import java.util.HashMap;
 43  
 import java.util.Map;
 44  
 
 45  
 import org.apache.log4j.Logger;
 46  
 import org.mindswap.pellet.jena.PelletReasonerFactory;
 47  
 
 48  
 import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
 49  
 import com.hp.hpl.jena.ontology.OntModel;
 50  
 import com.hp.hpl.jena.ontology.OntModelSpec;
 51  
 import com.hp.hpl.jena.rdf.model.Model;
 52  
 import com.hp.hpl.jena.rdf.model.ModelFactory;
 53  
 import com.hp.hpl.jena.rdf.model.Property;
 54  
 import com.hp.hpl.jena.rdf.model.Resource;
 55  
 import com.hp.hpl.jena.reasoner.Reasoner;
 56  
 
 57  
 /**
 58  
  * Export a SQL ResultSet to triples
 59  
  * 
 60  
  * @author David Read
 61  
  */
 62  
 public class RdbToRdf implements Runnable {
 63  
   /**
 64  
    * Logging instance
 65  
    */
 66  0
   private static final Logger LOGGER = Logger.getLogger(RdbToRdf.class);
 67  
 
 68  
   /**
 69  
    * Default namespace for the data loaded from the RDB
 70  
    */
 71  
   private static final String DEFAULT_NAMESPACE = "http://monead.com/semantic/utility";
 72  
 
 73  
   /**
 74  
    * Default class for all the exported records
 75  
    */
 76  
   private static final String DEFAULT_DATA_CLASS = "RdbData";
 77  
 
 78  
   /**
 79  
    * Used for formatting DB date column values into the ontology
 80  
    */
 81  0
   private static final SimpleDateFormat FORMAT_DATE = new SimpleDateFormat(
 82  
       "yyyy-MM-dd");
 83  
 
 84  
   /**
 85  
    * Used for formatting DB time column values into the ontology
 86  
    */
 87  0
   private static final SimpleDateFormat FORMAT_TIME = new SimpleDateFormat(
 88  
       "hh:mm:ss");
 89  
 
 90  
   /**
 91  
    * Used for formatting DB timestamp (date and time) column values into the
 92  
    * ontology
 93  
    */
 94  0
   private static final SimpleDateFormat FORMAT_DATE_TIME = new SimpleDateFormat(
 95  
       "yyyy-MM-dd'T'hh:mm:ss");
 96  
 
 97  
   /**
 98  
    * The namespace to use for the generated resources and predicates
 99  
    */
 100  
   private String rdfNamespace;
 101  
 
 102  
   /**
 103  
    * The class of the data instances generated
 104  
    */
 105  
   private String rdfDataClass;
 106  
 
 107  
   /**
 108  
    * The set of formats that can be output. These are defined by Jena
 109  
    */
 110  0
   private static final String[] FORMATS = {
 111  
       "Turtle",
 112  
       "N-Triples",
 113  
       "RDF/XML",
 114  
       "N3"
 115  
   };
 116  
 
 117  
   /**
 118  
    * The reasoning level to use
 119  
    * 
 120  
    * TODO allow this to be controlled from command line or configuration
 121  
    */
 122  
   private static final String REASONING_LEVEL = "none";
 123  
 
 124  
   /**
 125  
    * The output format for the triples
 126  
    * 
 127  
    * This will default to match the input format
 128  
    * 
 129  
    * TODO allow control from command line or configuration
 130  
    */
 131  0
   private String outputFormat = "TURTLE";
 132  
 
 133  
   /**
 134  
    * The reasoning levels available.
 135  
    */
 136  0
   protected static final String[] REASONING_LEVELS = {
 137  
       "none",
 138  
       "rdfs",
 139  
       "owl"
 140  
   };
 141  
 
 142  
   /**
 143  
    * Constant used if a value cannot be found in an array
 144  
    */
 145  
   private static final int UNKNOWN = -1;
 146  
 
 147  
   /**
 148  
    * The name (and path if necessary) to the output file for the output
 149  
    * triples
 150  
    */
 151  
   private String outputFileName;
 152  
 
 153  
   /**
 154  
    * The loaded ontology
 155  
    */
 156  
   private OntModel ontModel;
 157  
 
 158  
   /**
 159  
    * The query returning the result set
 160  
    */
 161  
   private String query;
 162  
 
 163  
   /**
 164  
    * The result set to be exported
 165  
    */
 166  
   private ResultSet resultSet;
 167  
 
 168  
   /**
 169  
    * The metadata associated with the result set
 170  
    */
 171  
   private ResultSetMetaData resultSetMetaData;
 172  
 
 173  
   /**
 174  
    * Collection of datatype properties already encountered
 175  
    */
 176  
   private Map<String, String> datatypeProperties;
 177  
 
 178  
   /**
 179  
    * Count of DB rows exported as of last execution of this instance
 180  
    */
 181  
   private long latestNumberOfRowsExported;
 182  
 
 183  
   /**
 184  
    * Constructor - sets up the input and output file paths and the triples map
 185  
    * 
 186  
    * @param pOutputFileName
 187  
    *          The name (and optional path) for the output
 188  
    * @param pQuery
 189  
    *          The query associated with the result set
 190  
    * @param pResultSet
 191  
    *          The database result set to export
 192  
    */
 193  0
   public RdbToRdf(String pOutputFileName, String pQuery, ResultSet pResultSet) {
 194  0
     LOGGER.info("Startup outputFileName:" + pOutputFileName);
 195  0
     setOutputFileName(pOutputFileName);
 196  0
     setQuery(pQuery);
 197  0
     setResultSet(pResultSet);
 198  
 
 199  
     try {
 200  0
       setResultSetMetaData(pResultSet.getMetaData());
 201  0
     } catch (SQLException sqlExc) {
 202  0
       throw new IllegalStateException(
 203  
           "Unable to access result set meta data from results", sqlExc);
 204  0
     }
 205  
 
 206  0
     rdfNamespace = DEFAULT_NAMESPACE + "#";
 207  0
     rdfDataClass = DEFAULT_DATA_CLASS;
 208  
 
 209  0
     datatypeProperties = new HashMap<String, String>();
 210  0
   }
 211  
 
 212  
   /**
 213  
    * Perform the steps to load, compare and report on the ontology
 214  
    */
 215  
   public void run() {
 216  0
     LOGGER.info("Load model with reasoner: " + REASONING_LEVEL);
 217  
 
 218  0
     latestNumberOfRowsExported = 0;
 219  
 
 220  0
     loadModel(REASONING_LEVEL);
 221  
 
 222  0
     loadModelFromRdb();
 223  
 
 224  0
     storeModel();
 225  0
   }
 226  
 
 227  
   /**
 228  
    * Setup the ontology model from the data anbd metadata in the result set
 229  
    */
 230  
   private void loadModelFromRdb() {
 231  
     ResultSet lResultSet;
 232  
     ResultSetMetaData lResultSetMetaData;
 233  
     int numColumns;
 234  
     String namespace;
 235  
     int realColumn;
 236  
     String className;
 237  0
     long recordCount = 0;
 238  
 
 239  0
     lResultSet = null;
 240  
 
 241  
     // Create the class for all the exported data
 242  0
     ontModel.createClass(rdfNamespace + rdfDataClass);
 243  
 
 244  
     // Access the database, run the query and create the triples
 245  
     try {
 246  0
       lResultSet = getResultSet();
 247  0
       lResultSetMetaData = getResultSetMetaData();
 248  0
       numColumns = lResultSetMetaData.getColumnCount();
 249  
 
 250  0
       LOGGER.debug("Catalog:" + lResultSetMetaData.getCatalogName(1)
 251  
           + " Schema:" + lResultSetMetaData.getSchemaName(1)
 252  
           + " Table:" + lResultSetMetaData.getTableName(1));
 253  
 
 254  
       // Default namespace
 255  0
       namespace = DEFAULT_NAMESPACE;
 256  
 
 257  
       // Default class name
 258  0
       className = rdfDataClass;
 259  
 
 260  
       // Create table-specific namespace and class name if possible
 261  0
       realColumn = 0;
 262  0
       for (int columnNum = 1; realColumn == 0
 263  0
           && columnNum <= lResultSetMetaData.getColumnCount(); ++columnNum) {
 264  0
         if (lResultSetMetaData.getTableName(columnNum).trim().length() > 0) {
 265  0
           realColumn = columnNum;
 266  
         }
 267  
       }
 268  
 
 269  0
       if (realColumn > 0) {
 270  
         // Namespace
 271  0
         if (lResultSetMetaData.getCatalogName(realColumn).trim()
 272  
             .length() > 0) {
 273  0
           namespace += "/"
 274  
               + lResultSetMetaData.getCatalogName(realColumn);
 275  
         }
 276  0
         if (lResultSetMetaData.getSchemaName(realColumn).trim().length() > 0) {
 277  0
           namespace += "/"
 278  
               + lResultSetMetaData.getSchemaName(realColumn);
 279  
         }
 280  0
         if (lResultSetMetaData.getTableName(realColumn).trim().length() > 0) {
 281  0
           namespace += "/"
 282  
               + lResultSetMetaData.getTableName(realColumn);
 283  
         }
 284  
 
 285  
         // Class name
 286  0
         if (lResultSetMetaData.getTableName(realColumn).trim().length() > 0) {
 287  0
           className = convertToClassName(lResultSetMetaData
 288  
               .getTableName(realColumn));
 289  
         }
 290  
       } else {
 291  0
         namespace += "/" + "global";
 292  
       }
 293  
 
 294  
       // Define a base URI
 295  
       // TODO Make this an option to enable/disable
 296  
       // ontModel.setNsPrefix("", namespace + "/base" + "#");
 297  
 
 298  
       // Define this as an ontology
 299  
       // TODO Make this an option to enable/disable
 300  
       // ontModel.createOntology(URIref.encode(getOutputFileName().replaceAll("\\\\",
 301  
       // "/")));
 302  
 
 303  0
       namespace += "#";
 304  
 
 305  
       // Prefixes
 306  0
       ontModel.setNsPrefix("bqbase", rdfNamespace);
 307  0
       ontModel.setNsPrefix("bqexport", namespace);
 308  
 
 309  
       // Create the class for this exported table
 310  0
       ontModel.createClass(namespace + className);
 311  
 
 312  
       // Add query as class description
 313  0
       ontModel.add(ontModel.createResource(namespace + className),
 314  
           ontModel.createAnnotationProperty(namespace + "sourceQuery"),
 315  
           getQuery(), XSDDatatype.XSDstring);
 316  
 
 317  
       // addStatement(rdfDataClass, "a", "owl:Class", namespace);
 318  
 
 319  0
       while (lResultSet.next()) {
 320  0
         ++recordCount;
 321  0
         addInstance(recordCount + "", namespace, className);
 322  0
         for (int col = 1; col <= numColumns; ++col) {
 323  0
           addStatement(recordCount + "",
 324  
                 lResultSetMetaData.getColumnLabel(col),
 325  
                 lResultSet.getString(col),
 326  
               lResultSetMetaData.getColumnType(col),
 327  
               namespace, className);
 328  
         }
 329  
       }
 330  0
     } catch (SQLException sqlExc) {
 331  0
       LOGGER.error("Error accessing the database", sqlExc);
 332  0
       throw new IllegalStateException("Error accessing the database",
 333  
           sqlExc);
 334  0
     }
 335  
 
 336  0
     latestNumberOfRowsExported = recordCount;
 337  0
   }
 338  
 
 339  
   /**
 340  
    * Add the PK value as a new instance of the data class. The name is
 341  
    * prepended with the DEFAULT_INSTANCE_NAME_PREFIX to prevent issues with
 342  
    * values that start with a digit.
 343  
    * 
 344  
    * This method also adds an RDF label containing the actual value
 345  
    * 
 346  
    * @param subject
 347  
    *          The subject which will be a class instance
 348  
    * @param namespace
 349  
    *          The namespace for the exported data
 350  
    * @param className
 351  
    *          The class name for the individuals representing the rows of data
 352  
    */
 353  
   private void addInstance(String subject, String namespace,
 354  
       String className) {
 355  
     Resource resource;
 356  
     Property property;
 357  
     Resource object;
 358  
 
 359  
     // LOGGER.debug("Add subject as class instance: " + subject);
 360  
 
 361  
     // subject is instance of the RdbData class
 362  0
     resource = ontModel.createResource(namespace + className + "_"
 363  
         + convertToInstanceName(makeSafeURIValue(subject)));
 364  0
     property = ontModel
 365  
         .createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
 366  0
     object = ontModel.createResource(rdfNamespace + rdfDataClass);
 367  0
     ontModel.add(resource, property, object);
 368  
 
 369  
     // And an instance of the specific table class
 370  0
     object = ontModel.createResource(namespace + className);
 371  0
     ontModel.add(resource, property, object);
 372  
 
 373  
     // Add the actual subject value as a label
 374  0
     property = ontModel
 375  
         .createProperty("http://www.w3.org/2000/01/rdf-schema#label");
 376  0
     ontModel.add(resource, property, subject);
 377  0
   }
 378  
 
 379  
   /**
 380  
    * Add the RDB data, treating the column data as a literal value
 381  
    * 
 382  
    * @param subject
 383  
    *          The subject of the triple
 384  
    * @param predicate
 385  
    *          The predicate of the triple
 386  
    * @param objectLiteral
 387  
    *          The object of the triple (treated as a literal)
 388  
    * @param rdbColumnType
 389  
    *          The SQL data type of the column containing this literal value
 390  
    * @param namespace
 391  
    *          The namespace for the exported data
 392  
    * @param className
 393  
    *          The class name for the individuals representing the rows of data
 394  
    */
 395  
   private void addStatement(String subject, String predicate,
 396  
       String objectLiteral, int rdbColumnType, String namespace,
 397  
       String className) {
 398  
     Resource resource;
 399  
     Property property;
 400  
     String formattedLiteral;
 401  
     XSDDatatype xsdDataType;
 402  
 
 403  0
     if (objectLiteral == null) {
 404  0
       return; // EARLY RETURN - Configured to Skip Null Columns
 405  
     }
 406  
 
 407  
     // Add the data as a triple
 408  0
     resource = ontModel.createResource(namespace + className + "_"
 409  
         + convertToInstanceName(makeSafeURIValue(subject)));
 410  0
     property = ontModel.createProperty(namespace
 411  
         + convertToPropertyName(makeSafeURIValue(predicate)));
 412  
 
 413  
     // LOGGER.debug("Add statement to model: " + resource + "->" + property
 414  
     // + "->" + objectLiteral);
 415  
 
 416  0
     switch (rdbColumnType) {
 417  
       case Types.BIGINT:
 418  
       case Types.INTEGER:
 419  
       case Types.SMALLINT:
 420  
       case Types.TINYINT:
 421  0
         xsdDataType = XSDDatatype.XSDinteger;
 422  0
         formattedLiteral = Long.parseLong(objectLiteral) + "";
 423  0
         break;
 424  
       case Types.DECIMAL:
 425  
       case Types.DOUBLE:
 426  
       case Types.FLOAT:
 427  
       case Types.NUMERIC:
 428  
       case Types.REAL:
 429  0
         xsdDataType = XSDDatatype.XSDdouble;
 430  0
         formattedLiteral = Double.parseDouble(objectLiteral) + "";
 431  0
         break;
 432  
       case Types.DATE:
 433  0
         xsdDataType = XSDDatatype.XSDdate;
 434  
         try {
 435  0
           formattedLiteral = FORMAT_DATE.format(FORMAT_DATE
 436  
               .parse(objectLiteral));
 437  0
         } catch (Throwable throwable) {
 438  0
           LOGGER.error("Cannot parse DB date: " + objectLiteral);
 439  0
           xsdDataType = XSDDatatype.XSDstring;
 440  0
           formattedLiteral = objectLiteral;
 441  0
         }
 442  0
         break;
 443  
       case Types.TIME:
 444  0
         xsdDataType = XSDDatatype.XSDtime;
 445  
         try {
 446  0
           formattedLiteral = FORMAT_TIME.format(FORMAT_TIME
 447  
               .parse(objectLiteral));
 448  0
         } catch (Throwable throwable) {
 449  0
           LOGGER.error("Cannot parse DB time: " + objectLiteral);
 450  0
           xsdDataType = XSDDatatype.XSDstring;
 451  0
           formattedLiteral = objectLiteral;
 452  0
         }
 453  0
         break;
 454  
       case Types.TIMESTAMP:
 455  0
         xsdDataType = XSDDatatype.XSDdateTime;
 456  
         try {
 457  0
           formattedLiteral = FORMAT_DATE_TIME.format(FORMAT_DATE_TIME
 458  
               .parse(objectLiteral));
 459  0
         } catch (Throwable throwable) {
 460  0
           LOGGER.error("Cannot parse DB timestamp (date and time): "
 461  
               + objectLiteral);
 462  0
           xsdDataType = XSDDatatype.XSDstring;
 463  0
           formattedLiteral = objectLiteral;
 464  0
         }
 465  0
         break;
 466  
       case Types.CHAR:
 467  
       case Types.VARCHAR:
 468  
       default:
 469  0
         xsdDataType = XSDDatatype.XSDstring;
 470  0
         formattedLiteral = objectLiteral;
 471  
         break;
 472  
     }
 473  
 
 474  
     // Data type identified from DB
 475  
     // ontModel.add(resource, ontModel.createProperty(namespace
 476  
     // + convertToPropertyName(makeSafeURIValue("colType_" + predicate))),
 477  
     // rdbColumnType + "", XSDDatatype.XSDinteger);
 478  
 
 479  
     // Literal value from DB record
 480  0
     ontModel.add(resource, property, formattedLiteral, xsdDataType);
 481  
 
 482  
     // Check if this is a new owl:DatatypeProperty
 483  0
     makeDatatypeProperty(namespace,
 484  
         convertToPropertyName(makeSafeURIValue(predicate)));
 485  0
   }
 486  
 
 487  
   /**
 488  
    * Check to see if this property URI has been asserted as an
 489  
    * owl:DatatypeProperty. If not, assert it.
 490  
    * 
 491  
    * @param namespace
 492  
    *          The namespace of the property
 493  
    * @param propertyName
 494  
    *          The name of the property
 495  
    */
 496  
   private void makeDatatypeProperty(String namespace, String propertyName) {
 497  
     Resource subject;
 498  
     Property predicate;
 499  
     Resource object;
 500  
 
 501  0
     if (datatypeProperties.get(namespace + propertyName) == null) {
 502  0
       subject = ontModel.createResource(namespace + propertyName);
 503  0
       predicate = ontModel
 504  
           .createProperty("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
 505  0
       object = ontModel
 506  
           .createResource("http://www.w3.org/2002/07/owl#DatatypeProperty");
 507  0
       ontModel.add(subject, predicate, object);
 508  
 
 509  0
       datatypeProperties.put(namespace + propertyName, "Y");
 510  
     }
 511  
 
 512  0
   }
 513  
 
 514  
   /**
 515  
    * Very crude method to create a value that will work as an RDF resource -
 516  
    * e.g. removes spaces. If the data contains other special characters then
 517  
    * this function will need to be fleshed out.
 518  
    * 
 519  
    * @param value
 520  
    *          the value to be made URI-safe
 521  
    * 
 522  
    * @return a URI-safe value (no spaces)
 523  
    */
 524  
   private static String makeSafeURIValue(String value) {
 525  0
     return value.replaceAll(" ", "_");
 526  
   }
 527  
 
 528  
   /**
 529  
    * Writes the triples to a data file.
 530  
    * 
 531  
    */
 532  
   private void storeModel() {
 533  
     FileWriter out;
 534  
 
 535  0
     out = null;
 536  
 
 537  0
     LOGGER.info("Write loaded data to file, " + outputFileName
 538  
         + ", in format: " + outputFormat);
 539  
 
 540  
     try {
 541  0
       out = new FileWriter(outputFileName, false);
 542  0
       ontModel.write(out, outputFormat);
 543  0
     } catch (IOException ioExc) {
 544  0
       LOGGER.error("Unable to write to file: " + outputFileName, ioExc);
 545  0
       throw new RuntimeException("unable to write output file ("
 546  
           + outputFileName + ")", ioExc);
 547  
     } finally {
 548  0
       if (out != null) {
 549  
         try {
 550  0
           out.close();
 551  0
         } catch (Throwable throwable) {
 552  0
           LOGGER.error("Failed to close output file: "
 553  
               + outputFileName, throwable);
 554  0
           throw new RuntimeException("Failed to close output file",
 555  
               throwable);
 556  0
         }
 557  
       }
 558  
     }
 559  0
   }
 560  
 
 561  
   /**
 562  
    * Get the set of defined ontology file formats that the program can load as
 563  
    * a CSV list String
 564  
    * 
 565  
    * @return The known ontology file formats as a CSV list
 566  
    */
 567  
   public static final String getFormatsAsCSV() {
 568  0
     return getArrayAsCSV(FORMATS);
 569  
   }
 570  
 
 571  
   /**
 572  
    * Create a CSV list from a String array
 573  
    * 
 574  
    * @param array
 575  
    *          An array
 576  
    * @return The array values in a CSV list
 577  
    */
 578  
   public static final String getArrayAsCSV(String[] array) {
 579  
     StringBuffer csv;
 580  
 
 581  0
     csv = new StringBuffer();
 582  
 
 583  0
     for (String value : array) {
 584  0
       if (csv.length() > 0) {
 585  0
         csv.append(", ");
 586  
       }
 587  0
       csv.append(value);
 588  
     }
 589  
 
 590  0
     return csv.toString();
 591  
 
 592  
   }
 593  
 
 594  
   /**
 595  
    * Set the output file name, where the report should be written
 596  
    * 
 597  
    * @param pOutputFileName
 598  
    *          The output file name
 599  
    */
 600  
   public void setOutputFileName(String pOutputFileName) {
 601  0
     outputFileName = pOutputFileName;
 602  0
   }
 603  
 
 604  
   /**
 605  
    * Get the output file name for the location of the generated report
 606  
    * 
 607  
    * @return The output file name
 608  
    */
 609  
   public String getOutputFileName() {
 610  0
     return outputFileName;
 611  
   }
 612  
 
 613  
   /**
 614  
    * Set the query returning the result set
 615  
    * 
 616  
    * @param pQuery
 617  
    *          The SQL query
 618  
    */
 619  
   private void setQuery(String pQuery) {
 620  0
     query = pQuery;
 621  0
   }
 622  
 
 623  
   /**
 624  
    * Get the query returning the result set
 625  
    * 
 626  
    * @return The SQL Query
 627  
    */
 628  
   private String getQuery() {
 629  0
     return query;
 630  
   }
 631  
 
 632  
   /**
 633  
    * Set the result set to be exported
 634  
    * 
 635  
    * @param pResultSet
 636  
    *          The result set
 637  
    */
 638  
   private void setResultSet(ResultSet pResultSet) {
 639  0
     resultSet = pResultSet;
 640  0
   }
 641  
 
 642  
   /**
 643  
    * Get the result set to be exported
 644  
    * 
 645  
    * @return The result set
 646  
    */
 647  
   private ResultSet getResultSet() {
 648  0
     return resultSet;
 649  
   }
 650  
 
 651  
   /**
 652  
    * Set the metadata for the result set to be exported
 653  
    * 
 654  
    * @param pResultSetMetaData
 655  
    *          The metadata
 656  
    */
 657  
   private void setResultSetMetaData(ResultSetMetaData pResultSetMetaData) {
 658  0
     resultSetMetaData = pResultSetMetaData;
 659  0
   }
 660  
 
 661  
   /**
 662  
    * Get the metadata for the result set to be exported
 663  
    * 
 664  
    * @return The metadata
 665  
    */
 666  
   private ResultSetMetaData getResultSetMetaData() {
 667  0
     return resultSetMetaData;
 668  
   }
 669  
 
 670  
   /**
 671  
    * Create a model with a reasoner set based on the chosen reasoning level.
 672  
    * 
 673  
    * @param reasoningLevel
 674  
    *          The reasoning level for this model
 675  
    * 
 676  
    * @return The created ontology model
 677  
    */
 678  
   private OntModel createModel(String reasoningLevel) {
 679  
     OntModel model;
 680  
     int reasoningLevelIndex;
 681  
 
 682  0
     model = null;
 683  
 
 684  0
     reasoningLevelIndex = getReasoningLevelIndex(reasoningLevel);
 685  
 
 686  0
     if (reasoningLevelIndex == 0) { // None
 687  0
       model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM);
 688  0
     } else if (reasoningLevelIndex == 1) { // RDFS
 689  0
       model = ModelFactory
 690  
           .createOntologyModel(OntModelSpec.OWL_DL_MEM_RDFS_INF);
 691  0
     } else if (reasoningLevelIndex == 2) { // OWL
 692  0
       final Reasoner reasoner = PelletReasonerFactory.theInstance().create();
 693  0
       final Model infModel = ModelFactory.createInfModel(reasoner,
 694  
           ModelFactory.createDefaultModel());
 695  0
       model = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM,
 696  
           infModel);
 697  
     }
 698  
 
 699  0
     return model;
 700  
   }
 701  
 
 702  
   /**
 703  
    * Obtain an ontology model set to the chosen reasoning level. Load the
 704  
    * ontology file into the model
 705  
    * 
 706  
    * @param reasoningLevel
 707  
    *          The selected reasoning level
 708  
    */
 709  
   private void loadModel(String reasoningLevel) {
 710  0
     ontModel = createModel(reasoningLevel);
 711  0
   }
 712  
 
 713  
   /**
 714  
    * Get the index position of the supplied reasoning level label
 715  
    * 
 716  
    * @param reasonerName
 717  
    *          A reasoning level label
 718  
    * 
 719  
    * @return The index position of the reasoning level. Will be equal to the
 720  
    *         constant UNKNOWN if the value cannot be found in the collection
 721  
    *         of known reasoning levels
 722  
    */
 723  
   public static final int getReasoningLevelIndex(String reasonerName) {
 724  0
     return getIndexValue(REASONING_LEVELS, reasonerName);
 725  
   }
 726  
 
 727  
   /**
 728  
    * Get the number of DB rows exported to triples as of the last exeuction of
 729  
    * this instance
 730  
    * 
 731  
    * @return The number of DB rows exported
 732  
    */
 733  
   public long getLatestNumberOfRowsExported() {
 734  0
     return latestNumberOfRowsExported;
 735  
   }
 736  
 
 737  
   /**
 738  
    * Find a String value within and array of Strings. Return the index
 739  
    * position where the value was found.
 740  
    * 
 741  
    * @param array
 742  
    *          An array of string to search
 743  
    * @param name
 744  
    *          The value to find in the array
 745  
    * 
 746  
    * @return The position where the value was found in the array. Will be
 747  
    *         equal to the constant UNKNOWN if the value cannot be found in the
 748  
    *         collection of known reasoning levels
 749  
    */
 750  
   public static final int getIndexValue(String[] array, String name) {
 751  
     Integer indexValue;
 752  
 
 753  0
     indexValue = null;
 754  
 
 755  0
     for (int index = 0; index < array.length && indexValue == null; ++index) {
 756  0
       if (array[index].toUpperCase().equals(name.toUpperCase())) {
 757  0
         indexValue = index;
 758  
       }
 759  
     }
 760  
 
 761  0
     return indexValue == null ? UNKNOWN : indexValue;
 762  
   }
 763  
 
 764  
   /**
 765  
    * Convert a string to a CamelCase format matching class naming convention
 766  
    * 
 767  
    * @param name
 768  
    *          The text to munge into a class name
 769  
    * 
 770  
    * @return The munged class name
 771  
    */
 772  
   private String convertToClassName(String name) {
 773  0
     return convertToCamelCase(name, true);
 774  
   }
 775  
 
 776  
   /**
 777  
    * Convert a string into a camelCase format matching property naming
 778  
    * convention
 779  
    * 
 780  
    * @param name
 781  
    *          The text to munge into a property name
 782  
    * 
 783  
    * @return The munged property name
 784  
    */
 785  
   private String convertToPropertyName(String name) {
 786  0
     return convertToCamelCase(name, false);
 787  
   }
 788  
 
 789  
   /**
 790  
    * Convert a string into a camelCase format matching instance naming
 791  
    * convention
 792  
    * 
 793  
    * @param name
 794  
    *          The text to munge into an instance (individual) name
 795  
    * 
 796  
    * @return The munged instance name
 797  
    */
 798  
   private String convertToInstanceName(String name) {
 799  0
     return convertToCamelCase(name, false);
 800  
   }
 801  
 
 802  
   /**
 803  
    * Convert a string into CamelCase or camelCase
 804  
    * 
 805  
    * @param name
 806  
    *          The string to convert to camel case
 807  
    * 
 808  
    * @param initialUpper
 809  
    *          Whether the resulting string should begin with an uppercase
 810  
    *          character
 811  
    * 
 812  
    * @return The camel case string
 813  
    */
 814  
   private String convertToCamelCase(String name, boolean initialUpper) {
 815  0
     final StringBuffer inCamelForm = new StringBuffer();
 816  0
     boolean nextUpper = initialUpper;
 817  0
     String fixName = name;
 818  
 
 819  0
     fixName = fixName.replaceAll("['(),]", "_");
 820  0
     final char[] chars = fixName.toCharArray();
 821  
 
 822  0
     for (char character : chars) {
 823  0
       if (character == '_') {
 824  0
         nextUpper = true;
 825  0
       } else if (nextUpper) {
 826  0
         inCamelForm.append(Character.toUpperCase(character));
 827  0
         nextUpper = false;
 828  
       } else {
 829  0
         inCamelForm.append(Character.toLowerCase(character));
 830  
       }
 831  
     }
 832  
 
 833  0
     return inCamelForm.toString();
 834  
   }
 835  
 }