/******************************************************************************* * Copyright (c) 2010-2011 VIVO Harvester Team. For full list of contributors, please see the AUTHORS file provided. * All rights reserved. * This program and the accompanying materials are made available under the terms of the new BSD license which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.html ******************************************************************************/ package org.vivoweb.harvester.util.repo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.vivoweb.harvester.util.InitLog; import org.vivoweb.harvester.util.FileAide; import org.vivoweb.harvester.util.args.ArgDef; import org.vivoweb.harvester.util.args.ArgList; import org.vivoweb.harvester.util.args.ArgParser; import org.vivoweb.harvester.util.args.UsageException; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.hp.hpl.jena.graph.GraphEvents; import com.hp.hpl.jena.query.Dataset; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QueryParseException; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.ResultSetFactory; import com.hp.hpl.jena.query.ResultSetFormatter; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.RDFWriter; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.sparql.resultset.ResultSetFormat; import com.hp.hpl.jena.update.UpdateAction; import com.hp.hpl.jena.update.UpdateFactory; /** * Connection Helper for Jena Models * @author Christopher Haines (hainesc@ctrip.ufl.edu) */ public abstract class JenaConnect { /** * SLF4J Logger */ private static Logger log = LoggerFactory.getLogger(JenaConnect.class); /** * Model we are connecting to */ private Model jenaModel; /** * The modelname */ private String modelName; /** * Factory (connects to the same jena triple store as another jena connect, but uses a different named model) * @param newModelName the model name to use * @return the new jenaconnect * @throws IOException unable to secure db connection */ public abstract JenaConnect neighborConnectClone(String newModelName) throws IOException; /** * Config Stream Based Factory that overrides parameters * @param configStream the config input stream * @param overrideParams the parameters to override the file with * @return JenaConnect instance * @throws IOException error connecting */ public static JenaConnect parseConfig(InputStream configStream, Map<String, String> overrideParams) throws IOException { Map<String, String> paramList = new JenaConnectConfigParser().parseConfig(configStream); if(overrideParams != null) { for(String key : overrideParams.keySet()) { paramList.put(key, overrideParams.get(key)); } } for(String param : paramList.keySet()) { if(!param.equalsIgnoreCase("dbUser") && !param.equalsIgnoreCase("dbPass")) { log.trace("'" + param + "' - '" + paramList.get(param) + "'"); } } return build(paramList); } /** * Config File Based Factory * @param configFileName the config file path * @return JenaConnect instance * @throws IOException xml parse error */ public static JenaConnect parseConfig(String configFileName) throws IOException { return parseConfig(configFileName, null); } /** * Config File Based Factory * @param configFileName the config file path * @param overrideParams the parameters to override the file with * @return JenaConnect instance * @throws IOException xml parse error */ public static JenaConnect parseConfig(String configFileName, Map<String, String> overrideParams) throws IOException { InputStream confStream = (configFileName == null) ? null : FileAide.getInputStream(configFileName); return parseConfig(confStream, overrideParams); } /** * Build a JenaConnect based on the given parameter set * @param params the value map * @return the JenaConnect * @throws IOException error connecting to jena model */ private static JenaConnect build(Map<String, String> params) throws IOException { // for(String param : params.keySet()) { // log.debug(param+" => "+params.get(param)); // } if((params == null) || params.isEmpty()) { return null; } if(!params.containsKey("type")) { throw new IllegalArgumentException("Must specify 'type' parameter {'rdb','sdb','tdb','file','mem'}"); } String type = params.get("type"); JenaConnect jc; if(type.equalsIgnoreCase("mem")) { jc = new MemJenaConnect(params.get("modelName")); } else if(type.equalsIgnoreCase("rdb")) { jc = new RDBJenaConnect(params.get("dbUrl"), params.get("dbUser"), params.get("dbPass"), params.get("dbType"), params.get("dbClass"), params.get("modelName")); } else if(type.equalsIgnoreCase("sdb")) { jc = new SDBJenaConnect(params.get("dbUrl"), params.get("dbUser"), params.get("dbPass"), params.get("dbType"), params.get("dbClass"), params.get("dbLayout"), params.get("modelName")); } else if(type.equalsIgnoreCase("tdb")) { jc = new TDBJenaConnect(params.get("dbDir"), params.get("modelName")); } else if(type.equalsIgnoreCase("file")) { jc = new FileJenaConnect(params.get("file"), params.get("rdfLang")); } else { throw new IllegalArgumentException("unknown type: " + type); } if((params.containsKey("checkEmpty") && (params.get("checkEmpty").toLowerCase() == "true")) && jc.isEmpty()) { StringBuilder emptyWarn = new StringBuilder("jena model empty! "); emptyWarn.append(type); emptyWarn.append(": "); if(!type.equalsIgnoreCase("mem")) { if(type.equalsIgnoreCase("tdb")) { emptyWarn.append("dbDir: "); emptyWarn.append(params.get("dbDir")); emptyWarn.append(" "); } else { emptyWarn.append("dbDir: "); emptyWarn.append(params.get("dbDir")); emptyWarn.append(" "); } } emptyWarn.append("modelName: "); emptyWarn.append(jc.getModelName()); JenaConnect.log.warn(emptyWarn.toString()); } return jc; } /** * Get the size of a jena model * @return the number of statement in this model * @throws IOException error connecting */ public int size() throws IOException { ResultSet resultSet = executeSelectQuery("SELECT (count(?s) as ?size) WHERE { ?s ?p ?o }"); // read first result if(resultSet.hasNext()) { //Display count return resultSet.next().get("size").asLiteral().getInt(); } return 0; } /** * Get the dataset for this connection Can be very expensive when using RDB connections (SDB, TDB, and Mem are fine) * @return the database connection's dataset * @throws IOException error connecting */ public abstract Dataset getDataset() throws IOException; /** * Load in RDF * @param in input stream to read rdf from * @param namespace the base uri to use for imported uris * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" */ public void loadRdfFromStream(InputStream in, String namespace, String language) { getJenaModel().read(in, namespace, language); } /** * Load the RDF from a file * @param fileName the file to read from * @param namespace the base uri to use for imported uris * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @throws IOException error accessing file */ public void loadRdfFromFile(String fileName, String namespace, String language) throws IOException { loadRdfFromStream(FileAide.getInputStream(fileName), namespace, language); } /** * Load in RDF * @param rdf rdf string * @param namespace the base uri to use for imported uris * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" */ public void loadRdfFromString(String rdf, String namespace, String language) { loadRdfFromStream(new ByteArrayInputStream(rdf.getBytes()), namespace, language); } /** * Load in RDF from a model * @param jc the model to load in */ public void loadRdfFromJC(JenaConnect jc) { getJenaModel().add(jc.getJenaModel()); } /** * Export all RDF * @param out output stream to write rdf to * @throws IOException error writing to stream */ public void exportRdfToStream(OutputStream out) throws IOException { exportRdfToStream(out, null); } /** * Export all RDF * @param out output stream to write rdf to * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @throws IOException error writing to stream */ public void exportRdfToStream(OutputStream out, String language) throws IOException { exportRdfToStream(this.jenaModel, out, language); } /** * Export all RDF * @param m the model to export from * @param out output stream to write rdf to * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @throws IOException error writing to stream */ private static void exportRdfToStream(Model m, OutputStream out, String language) throws IOException { RDFWriter fasterWriter = m.getWriter(language); fasterWriter.setProperty("showXmlDeclaration", "true"); fasterWriter.setProperty("allowBadURIs", "true"); fasterWriter.setProperty("relativeURIs", ""); OutputStreamWriter osw = new OutputStreamWriter(out, Charset.availableCharsets().get("UTF-8")); fasterWriter.write(m, osw, ""); osw.flush(); out.flush(); } /** * Export all RDF * @return the rdf * @throws IOException error writing to string */ public String exportRdfToString() throws IOException { return exportRdfToString(null); } /** * Export all RDF * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @return the rdf * @throws IOException error writing to string */ public String exportRdfToString(String language) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); exportRdfToStream(baos, language); return baos.toString(); } /** * Export the RDF to a file * @param fileName the file to write to * @throws IOException error writing to file */ public void exportRdfToFile(String fileName) throws IOException { exportRdfToFile(fileName, null); } /** * Export the RDF to a file * @param fileName the file to write to * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @throws IOException error writing to file */ public void exportRdfToFile(String fileName, String language) throws IOException { exportRdfToFile(fileName, language, false); } /** * Export the RDF to a file * @param fileName the file to write to * @param append append to the file * @throws IOException error writing to file */ public void exportRdfToFile(String fileName, boolean append) throws IOException { exportRdfToFile(fileName, null, append); } /** * Export the RDF to a file * @param fileName the file to write to * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @param append append to the file * @throws IOException error writing to file */ public void exportRdfToFile(String fileName, String language, boolean append) throws IOException { exportRdfToStream(FileAide.getOutputStream(fileName, append), language); } /** * Remove RDF from another JenaConnect * @param inputJC the Model to read from */ public void removeRdfFromJC(JenaConnect inputJC) { this.jenaModel.remove(inputJC.getJenaModel()); } /** * Remove RDF from an input stream * @param in input stream to read rdf from * @param namespace the base uri to use for imported uris * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" */ public void removeRdfFromStream(InputStream in, String namespace, String language) { removeRdfFromJC(new MemJenaConnect(in, namespace, language)); } /** * Remove the RDF from a file * @param fileName the file to read from * @param namespace the base uri to use for imported uris * @param language the language the rdf is in. Predefined values for lang are "RDF/XML", "N-TRIPLE", "TURTLE" (or * "TTL") and "N3". null represents the default language, "RDF/XML". "RDF/XML-ABBREV" is a synonym for * "RDF/XML" * @throws IOException error connecting */ public void removeRdfFromFile(String fileName, String namespace, String language) throws IOException { removeRdfFromStream(FileAide.getInputStream(fileName), namespace, language); } /** * Removes all records in a RecordHandler from the model * @param rh the RecordHandler to pull records from * @param namespace the base uri to use for imported uris * @param language the rdf syntax language (RDF/XML, N3, TTL, etc). null = RDF/XML * @return number of records removed */ public int removeRdfFromRH(RecordHandler rh, String namespace, String language) { int processCount = 0; for(Record r : rh) { log.trace("removing record: " + r.getID()); if(namespace != null) { // log.trace("using namespace '"+namespace+"'"); } ByteArrayInputStream bais = new ByteArrayInputStream(r.getData().getBytes()); getJenaModel().remove(new MemJenaConnect(bais, namespace, language).getJenaModel()); try { bais.close(); } catch(IOException e) { // ignore } processCount++; } return processCount; } /** * Adds all records in a RecordHandler to the model * @param rh the RecordHandler to pull records from * @param namespace the base uri to use for imported uris * @param language the rdf syntax language (RDF/XML, N3, TTL, etc). null = RDF/XML * @return number of records added */ public int loadRdfFromRH(RecordHandler rh, String namespace, String language) { int processCount = 0; for(Record r : rh) { log.trace("loading record: " + r.getID()); if(namespace != null) { // log.trace("using namespace '"+namespace+"'"); } ByteArrayInputStream bais = new ByteArrayInputStream(r.getData().getBytes()); getJenaModel().read(bais, namespace, language); try { bais.close(); } catch(IOException e) { // ignore } processCount++; } return processCount; } /** * Closes the model */ public void close() { sync(); } /** * Syncronizes the model to the datastore */ public abstract void sync(); /** * Build a QueryExecution from a queryString * @param queryString the query to build execution for * @param datasetMode execute against dataset * @return the QueryExecution * @throws IOException error connecting */ private QueryExecution buildQueryExec(String queryString, boolean datasetMode) throws IOException { QueryExecution qe; if(datasetMode) { qe = QueryExecutionFactory.create(QueryFactory.create(queryString, Syntax.syntaxARQ), getDataset()); } else { qe = QueryExecutionFactory.create(QueryFactory.create(queryString, Syntax.syntaxARQ), getJenaModel()); } return qe; } /** * Executes a sparql select query against the JENA model and returns the selected result set * @param queryString the query to execute against the model * @return the executed query result set * @throws IOException error connecting */ public ResultSet executeSelectQuery(String queryString) throws IOException { return executeSelectQuery(queryString, false, false); } /** * Executes a sparql select query against the JENA model and returns the selected result set * @param queryString the query to execute against the model * @param datasetMode execute against dataset * @return the executed query result set * @throws IOException error connecting */ public ResultSet executeSelectQuery(String queryString, boolean datasetMode) throws IOException { return executeSelectQuery(queryString, false, datasetMode); } /** * Executes a sparql select query against the JENA model and returns the selected result set * @param queryString the query to execute against the model * @param copyResultSet copy the resultset * @param datasetMode execute against dataset * @return the executed query result set * @throws IOException error connecting */ public ResultSet executeSelectQuery(String queryString, boolean copyResultSet, boolean datasetMode) throws IOException { QueryExecution qexec = buildQueryExec(queryString, datasetMode); ResultSet rs = qexec.execSelect(); if(copyResultSet) { rs = ResultSetFactory.copyResults(rs); qexec.close(); } return rs; } /** * Executes a sparql construct query against the JENA model and returns the constructed result model * @param queryString the query to execute against the model * @return the executed query result model * @throws IOException error connecting */ public JenaConnect executeConstructQuery(String queryString) throws IOException { return executeConstructQuery(queryString, false); } /** * Executes a sparql construct query against the JENA model and returns the constructed result model * @param queryString the query to execute against the model * @param datasetMode execute against dataset * @return the executed query result model * @throws IOException error connecting */ public JenaConnect executeConstructQuery(String queryString, boolean datasetMode) throws IOException { JenaConnect jc = new MemJenaConnect(); jc.getJenaModel().add(buildQueryExec(queryString, datasetMode).execConstruct()); return jc; } /** * Executes a sparql describe query against the JENA model and returns the description result model * @param queryString the query to execute against the model * @return the executed query result model * @throws IOException error connecting */ public JenaConnect executeDescribeQuery(String queryString) throws IOException { return executeDescribeQuery(queryString, false); } /** * Executes a sparql describe query against the JENA model and returns the description result model * @param queryString the query to execute against the model * @param datasetMode execute against dataset * @return the executed query result model * @throws IOException error connecting */ public JenaConnect executeDescribeQuery(String queryString, boolean datasetMode) throws IOException { JenaConnect jc = new MemJenaConnect(); jc.getJenaModel().add(buildQueryExec(queryString, datasetMode).execDescribe()); return jc; } /** * Executes a sparql describe query against the JENA model and returns the description result model * @param queryString the query to execute against the model * @return the executed query result model * @throws IOException error connecting */ public boolean executeAskQuery(String queryString) throws IOException { return executeAskQuery(queryString, false); } /** * Executes a sparql describe query against the JENA model and returns the description result model * @param queryString the query to execute against the model * @param datasetMode execute against dataset * @return the executed query result model * @throws IOException error connecting */ public boolean executeAskQuery(String queryString, boolean datasetMode) throws IOException { return buildQueryExec(queryString, datasetMode).execAsk(); } /** * Executes a sparql update query against the JENA model * @param queryString the query to execute against the model * @throws IOException error connecting */ public void executeUpdateQuery(String queryString) throws IOException { executeUpdateQuery(queryString, false); } /** * Executes a sparql update query against the JENA model * @param queryString the query to execute against the model * @param datasetMode execute against dataset * @throws IOException error connecting */ public void executeUpdateQuery(String queryString, boolean datasetMode) throws IOException { this.jenaModel.begin(); this.jenaModel.notifyEvent(GraphEvents.startRead); try { // log.debug("query:\n" + queryString); if(datasetMode) { // log.trace("Executing query against dataset"); UpdateAction.execute(UpdateFactory.create(queryString), getDataset()); } else { // log.trace("Executing query against model"); UpdateAction.execute(UpdateFactory.create(queryString), getJenaModel()); } } finally { this.jenaModel.notifyEvent(GraphEvents.finishRead); this.jenaModel.commit(); } } /** * RDF formats */ protected static HashMap<String, ResultSetFormat> formatSymbols = new HashMap<String, ResultSetFormat>(); static { formatSymbols.put(ResultSetFormat.syntaxXML.getSymbol(), ResultSetFormat.syntaxXML); formatSymbols.put(ResultSetFormat.syntaxRDF_XML.getSymbol(), ResultSetFormat.syntaxRDF_XML); formatSymbols.put(ResultSetFormat.syntaxRDF_N3.getSymbol(), ResultSetFormat.syntaxRDF_N3); formatSymbols.put(ResultSetFormat.syntaxCSV.getSymbol(), ResultSetFormat.syntaxCSV); formatSymbols.put(ResultSetFormat.syntaxText.getSymbol(), ResultSetFormat.syntaxText); formatSymbols.put(ResultSetFormat.syntaxJSON.getSymbol(), ResultSetFormat.syntaxJSON); } /** * Execute a Query and output result to System.out * @param queryParam the query * @param resultFormatParam the format to return the results in ('RS_RDF',etc for select queries / 'RDF/XML',etc for * construct/describe queries) * @param datasetMode run against dataset rather than model * @throws IOException error writing to output */ public void executeQuery(String queryParam, String resultFormatParam, boolean datasetMode) throws IOException { executeQuery(queryParam, resultFormatParam, null, datasetMode); } /** * Execute a Query * @param queryParam the query * @param resultFormatParam the format to return the results in ('RS_TEXT' default for select queries / 'RDF/XML' * default for construct/describe queries) * @param output output stream to write to - null uses System.out * @param datasetMode run against dataset rather than model * @throws IOException error writing to output */ public void executeQuery(String queryParam, String resultFormatParam, OutputStream output, boolean datasetMode) throws IOException { OutputStream out; if(output != null) { out = output; log.info("Outputting to the specified location"); } else { out = System.out; } QueryExecution qe = null; try { Query query = QueryFactory.create(queryParam, Syntax.syntaxARQ); if(datasetMode) { // log.trace("Executing query against dataset"); qe = QueryExecutionFactory.create(query, getDataset()); } else { // log.trace("Executing query against model"); qe = QueryExecutionFactory.create(query, getJenaModel()); } if(query.isSelectType()) { ResultSetFormat rsf = formatSymbols.get(resultFormatParam); if(rsf == null) { rsf = ResultSetFormat.syntaxText; } ResultSetFormatter.output(out, qe.execSelect(), rsf); } else if(query.isAskType()) { out.write((Boolean.toString(qe.execAsk())+"\n").getBytes()); } else { MemJenaConnect resultModel = new MemJenaConnect(); if(query.isConstructType()) { qe.execConstruct(resultModel.getJenaModel()); } else if(query.isDescribeType()) { qe.execDescribe(resultModel.getJenaModel()); } else { throw new IllegalArgumentException("Query Invalid: Not Select, Construct, Ask, or Describe"); } resultModel.exportRdfToStream(out, resultFormatParam); } } catch(QueryParseException e1) { try { executeUpdateQuery(queryParam, datasetMode); log.info("Update Successfully Applied"); } catch(QueryParseException e2) { log.error("Invalid Query:\n"+queryParam); log.trace("Attempted Query Exception:",e1); log.trace("Attempted Update Exception:",e2); } } finally { if(qe != null) { qe.close(); } } } /** * Accessor for Jena Model * @return the Jena Model */ public Model getJenaModel() { return this.jenaModel; } /** * Setter * @param jena the new model */ protected void setJenaModel(Model jena) { this.jenaModel = jena; } /** * Checks if the model contains the given uri * @param uri the uri to check for * @return true if found, false otherwise * @throws IOException error connecting */ public boolean containsURI(String uri) throws IOException { return executeAskQuery("ASK { <" + uri + "> ?p ?o }"); } /** * Get the ArgParser for this task * @return the ArgParser */ private static ArgParser getParser() { ArgParser parser = new ArgParser("JenaConnect"); parser.addArgument(new ArgDef().setShortOption('j').setLongOpt("jena").withParameter(true, "CONFIG_FILE").setDescription("config file for jena model").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('J').setLongOpt("jenaOverride").withParameterValueMap("JENA_PARAM", "VALUE").setDescription("override the JENA_PARAM of jena model config using VALUE").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('q').setLongOpt("query").withParameter(true, "SPARQL_QUERY").setDescription("sparql query to execute").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('Q').setLongOpt("queryResultFormat").withParameter(true, "RESULT_FORMAT").setDescription("the format to return the results in ('RS_RDF',etc for select queries / 'RDF/XML',etc for construct/describe queries)").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('f').setLongOpt("fileOutput").withParameter(true, "OUTPUT_FILE").setDescription("the file to output the results in, if not specified writes to stdout").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('d').setLongOpt("dataset").setDescription("execute query against dataset rather than model").setRequired(false)); parser.addArgument(new ArgDef().setShortOption('t').setLongOpt("truncate").setDescription("empty the jena model").setRequired(false)); return parser; } /** * Config parser for Jena Models * @author Christopher Haines (hainesc@ctrip.ufl.edu) */ private static class JenaConnectConfigParser extends DefaultHandler { /** * Param list from the config file */ private Map<String, String> params; /** * temporary storage for cdata */ private String tempVal; /** * temporary storage for param name */ private String tempParamName; /** * Default Constructor */ protected JenaConnectConfigParser() { this.params = new HashMap<String, String>(); this.tempVal = ""; this.tempParamName = ""; } /** * Build a JenaConnect using the input stream data * @param inputStream stream to read config from * @return the JenaConnect described by the stream * @throws IOException error reading stream */ protected Map<String, String> parseConfig(InputStream inputStream) throws IOException { if(inputStream != null) { // get a factory SAXParserFactory spf = SAXParserFactory.newInstance(); try { // get a new instance of parser SAXParser sp = spf.newSAXParser(); // parse the file and also register this class for call backs sp.parse(inputStream, this); } catch(SAXException e) { throw new IOException(e); } catch(ParserConfigurationException e) { throw new IOException(e); } } return this.params; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { this.tempVal = ""; this.tempParamName = ""; if(qName.equalsIgnoreCase("Param")) { this.tempParamName = attributes.getValue("name"); } else if(!qName.equalsIgnoreCase("Model") && !qName.equalsIgnoreCase("Config")) { throw new SAXException("Unknown Tag: " + qName); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { this.tempVal = new String(ch, start, length); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if(qName.equalsIgnoreCase("Param")) { this.params.put(this.tempParamName, this.tempVal); } else if(!qName.equalsIgnoreCase("Model") && !qName.equalsIgnoreCase("Config")) { throw new SAXException("Unknown Tag: " + qName); } } } /** * Remove all statements from model */ public void truncate() { Model sourceModel = getJenaModel(); sourceModel.enterCriticalSection(Lock.WRITE); try{ // this method is used so that any listeners can see each statement removed sourceModel.removeAll((Resource)null,(Property)null,(RDFNode)null); } finally { sourceModel.leaveCriticalSection(); } } /** * Set the modelName * @param modelName the model name */ protected void setModelName(String modelName) { this.modelName = modelName; } /** * Get the modelName * @return the modelName */ public String getModelName() { return this.modelName; } /** * Is this model empty * @return true if empty, false otherwise * @throws IOException error connecting */ public boolean isEmpty() throws IOException { return !executeAskQuery("ASK { ?s ?p ?o }"); } /** * Output the jena model information */ public void printParameters() { log.trace("modelName: '" + getModelName() + "'"); } /** * Run from commandline * @param args the commandline args * @throws IOException error parsing args * @throws UsageException user requested usage message */ public static void run(String... args) throws IOException, UsageException { ArgList argList = getParser().parse(args); JenaConnect jc = JenaConnect.parseConfig(argList.get("j"), argList.getValueMap("J")); if(jc == null) { throw new IllegalArgumentException("Must specify a jena model"); } if(argList.has("t")) { if(argList.has("q") || argList.has("Q")) { throw new IllegalArgumentException("Cannot Execute Query and Truncate"); } log.info("Removing all triples"); jc.truncate(); } else if(argList.has("q")) { jc.executeQuery(argList.get("q"), argList.get("Q"), FileAide.getOutputStream(argList.get("f")), argList.has("d")); } else { throw new IllegalArgumentException("No Operation Specified"); } jc.sync(); } /** * Main method * @param args commandline arguments */ public static void main(String... args) { Exception error = null; try { InitLog.initLogger(args, getParser(), "ft"); log.info(getParser().getAppName() + ": Start"); run(args); } catch(IllegalArgumentException e) { log.error(e.getMessage()); log.debug("Stacktrace:",e); System.err.println(getParser().getUsage()); error = e; } catch(UsageException e) { log.info("Printing Usage:"); System.out.println(getParser().getUsage()); error = e; } catch(Exception e) { log.error(e.getMessage()); log.debug("Stacktrace:",e); error = e; } finally { log.info(getParser().getAppName() + ": End"); if(error != null) { System.exit(1); } } } }