Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
Jena is a Java framework for building Semantic Web applications. It provides a programmatic environment for RDF, RDFS and OWL, SPARQL and includes a rule-based inference engine.
/*
* (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
* All rights reserved.
*
*/
//=======================================================================
// Package
package com.hp.hpl.jena.db.impl;
//=======================================================================
// Imports
import java.sql.*;
import java.util.*;
import java.io.*;
import com.hp.hpl.jena.db.*;
import com.hp.hpl.jena.shared.JenaException;
import com.hp.hpl.jena.util.CollectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//=======================================================================
/**
* Stores a set of sql statements loaded from a resource file.
* Caches prepared versions of the statements for a given db connection.
*
* The resource file is located on the classpath and has the format:
*
* # comment at start of line
* operationName1
* sql code line 1
* ...
* sql code last line
*
* operationName2
* ...
*
* where the blank lines delimit one sql block from the next.
*
The sql code is typically a single SQL statement but some operations,
* specifically database initialization and cleanup may require a variable number
* of statments. To cater for this terminate each statement in those groups with
* the string ";;". Note that a single ";" is not used because these compound
* statements are often stored procedure definitions which end to have ";" line
* terminators!
*
* @author Dave Reynolds. Updated by hkuno to support GraphRDB.
* @version $Revision: 1.1 $ on $Date: 2009/06/29 08:55:37 $
*/
public class SQLCache {
//=======================================================================
// Variables
/** Set of sql statements indexed by operation name. */
protected Properties m_sql;
/** Cache of prepared versions of the statements. Each map entry is a list
* of copies of the prepared statement for multi-threaded apps. */
protected Map> m_preparedStatements = CollectionFactory.createHashedMap();
/** Track which cached, prepared statements are in use and the corresponding
* list to which the statement should be returned. */
protected Map> m_cachedStmtInUse = CollectionFactory.createHashedMap();
/** the packaged jdbc connection to the database itself. */
protected IDBConnection m_connection;
/** Maximum number of pre-prepared statements to keep for each operator. */
protected static final int MAX_PS_CACHE = 4;
/** Set to true to enable cache of pre-prepared statements. */
protected boolean CACHE_PREPARED_STATEMENTS = true;
static protected Logger logger = LoggerFactory.getLogger( SQLCache.class );
//=======================================================================
// Public interface
/**
* Constructor. Creates a new cache sql statements for interfacing to
* a specific database.
* @param sqlFile the name of the file of sql statements to load, this is
* loaded from the classpath.
* @param defaultOps Properties table which provides the default
* sql statements, any definitions of a given operation in the loaded file
* will override the default.
* @param connection the jdbc connection to the database itself
* @param idType the sql string to use for id types (substitutes for $id in files)
*/
public SQLCache(String sqlFile, Properties defaultOps, IDBConnection connection, String idType) throws IOException {
m_sql = loadSQLFile(sqlFile, defaultOps, idType);
m_connection = connection;
}
/**
* Set to true to enable cache of pre-prepared statements.
*/
public void setCachePreparedStatements(boolean state) {
CACHE_PREPARED_STATEMENTS = state;
}
/**
* Return true if cache of pre-prepared statements is enabled.
*/
public boolean getCachePreparedStatements() {
return CACHE_PREPARED_STATEMENTS;
}
/**
* Flush the cache of all currently prepared statements.
*/
public void flushPreparedStatementCache() throws RDFRDBException {
try {
Iterator> it = m_preparedStatements.values().iterator();
while (it.hasNext()) {
Iterator psit = it.next().iterator();
while (psit.hasNext()) {
psit.next().close();
}
}
} catch (SQLException e) {
throw new RDFRDBException("Problem flushing PS cache", e);
} finally {
m_preparedStatements = CollectionFactory.createHashedMap();
m_cachedStmtInUse = CollectionFactory.createHashedMap();
}
}
/**
* Return the associated jdbc connection.
*/
public Connection getConnection() throws SQLException {
return m_connection.getConnection();
}
/**
* Set the associated jdbc connection.
*/
public void setConnection(IDBConnection connection) {
m_connection = connection;
}
/**
* Return the raw SQL statement corresponding to the named operation.
*/
public String getSQLStatement(String opname) throws SQLException {
return getSQLStatement(opname, (String[]) null);
}
/**
* Return the raw SQL statement corresponding to the named operation.
* Substitute the ${a} attribute macro for the current attribute number.
*/
public String getSQLStatement(String opname, String[] attr) throws SQLException {
String cmd = m_sql.getProperty(opname);
if (cmd == null) {
if ( opname.startsWith("*") ) {
cmd = genSQLStatement(opname);
m_sql.setProperty(opname, cmd);
} else {
logger.error("Unable to find SQL for operation: " + opname);
throw new SQLException("Unable to find SQL for operation: " + opname);
}
}
int attrCnt = (attr == null) ? 0 : attr.length;
if ( attrCnt > 0 ) cmd = substitute(cmd, "${a}", attr[0]);
if ( attrCnt > 1 ) cmd = substitute(cmd, "${b}", attr[1]);
if ( attrCnt > 2 ) cmd = substitute(cmd, "${c}", attr[2]);
if ( attrCnt > 3 ) throw new JenaException("Too many arguments");
return cmd;
}
public String getSQLStatement(String opname, String attr) throws SQLException {
String[] param = {attr};
return getSQLStatement(opname,param);
}
/**
* Return the raw SQL statement corresponding to the named operation.
* Attribute version - substitute the ${a} attribute macro for
* the current attribute number.
*/
public String getSQLStatement(String opname, String attrA, String attrB) throws SQLException {
String[] param = {attrA,attrB};
return getSQLStatement(opname,param);
}
/**
* Return a set of raw SQL statements corresponding to the named operation.
* This is used for compound operations where more than one SQL command is needed to
* implement the operation (e.g. database formating and clean up). The
* individual statements should be separated by double-semicolons at the end of the line.
*
Needs refactoring to clarify what operations are and are not compound but for now
* it is assumed the caller knows which is correct. Compound statements are not called
* repeatedly so don't currently cache the parsed statement set.
*/
public Collection getSQLStatementGroup(String opname) throws SQLException {
String statementSrc = m_sql.getProperty(opname);
if (statementSrc == null) {
throw new SQLException("Unable to find SQL for operation: " + opname);
}
int start = 0;
int split = 0;
List statements = new LinkedList();
while (split != -1) {
split = statementSrc.indexOf(";;\n", start);
String statement = null;
if (split == -1) {
statement = statementSrc.substring(start);
} else {
statement = statementSrc.substring(start, split);
start = split +2;
}
if (!statement.trim().equals(""))
statements.add(statement);
}
return statements;
}
/**
* Return a prepared SQL statement corresponding to the named operation.
* The statement should either be closed after use or returned to the
* prepared statement pool using {@link #returnPreparedSQLStatement returnPreparedSQLStatement}
*
*
Only works for single statements, not compound statements.
* @param con the jdbc connection to use for preparing statements
* @param opname the name of the sql operation to locate
* @return a prepared SQL statement appropriate for the JDBC connection
* used when this SQLCache was constructed or null if there is no such
* operation or no such connection
*
*
*/
public synchronized PreparedStatement getPreparedSQLStatement(String opname, String [] attr) throws SQLException {
/* TODO extended calling format or statement format to support different
* result sets and conconcurrency modes.
*/
PreparedStatement ps=null;
if (m_connection == null || opname == null) return null;
int attrCnt = (attr == null) ? 0 : attr.length;
String aop = opname;
if ( attrCnt > 0 ) aop = concatOpName(aop, attr[0]);
if ( attrCnt > 1 ) aop = concatOpName(aop, attr[1]);
if ( attrCnt > 2 ) aop = concatOpName(aop, attr[2]);
if ( attrCnt > 3 ) throw new JenaException("Too many arguments");
List psl = m_preparedStatements.get(aop);
// OVERRIDE: added proper PreparedStatement removal.
if (psl!=null && !psl.isEmpty()) {
ps = psl.remove(0);
try{
ps.clearParameters();
}catch(SQLException e) {
ps.close();
}
}
if (ps == null) {
String sql = getSQLStatement(opname, attr);
if (sql == null) {
throw new SQLException("No SQL defined for operation: " + opname);
}
if (psl == null && CACHE_PREPARED_STATEMENTS) {
psl = new LinkedList();
m_preparedStatements.put(aop, psl);
}
ps = doPrepareSQLStatement(sql);
}
if ( CACHE_PREPARED_STATEMENTS ) m_cachedStmtInUse.put(ps,psl);
return ps;
}
/**
* Prepare a SQL statement for the given statement string.
*
*
Only works for single statements, not compound statements.
* @param stmt the sql statement to prepare.
* @return a prepared SQL statement appropriate for the JDBC connection
* used when this SQLCache was constructed or null if there is no such
* connection.
*/
private synchronized PreparedStatement doPrepareSQLStatement(String sql) throws SQLException {
if (m_connection == null) return null;
return getConnection().prepareStatement(sql);
}
/**
* Return a prepared SQL statement for the given statement string.
* The statement should either be closed after use.
*
*
Only works for single statements, not compound statements.
* @param stmt the sql statement to prepare.
* @return a prepared SQL statement appropriate for the JDBC connection
* used when this SQLCache was constructed or null if there is no such
* connection.
*/
public synchronized PreparedStatement prepareSQLStatement(String sql) throws SQLException {
if (m_connection == null) return null;
return doPrepareSQLStatement(sql);
}
public synchronized PreparedStatement getPreparedSQLStatement(String opname) throws SQLException {
return getPreparedSQLStatement(opname, (String[]) null);
}
/**
* Variant on {@link #getPreparedSQLStatement getPreparedSQLStatement} which
* accesses the attribute variant correspond to the given attribute suffix.
*/
public synchronized PreparedStatement getPreparedSQLStatement(String opname, String attr) throws SQLException {
String[] param = {attr};
return getPreparedSQLStatement(opname,param);
}
/**
* Variant on {@link #getPreparedSQLStatement getPreparedSQLStatement} which
* access the attribute variant correspond to the given attribute suffix.
*/
public synchronized PreparedStatement getPreparedSQLStatement(String opname, String attrA, String attrB) throws SQLException {
String[] param = {attrA,attrB};
return getPreparedSQLStatement(opname,param);
}
/**
* Return a prepared statement to the statement pool for reuse by
* another caller. Any close problems logged rather than raising exception
* so that iterator close() operations can be silent so that they can meet
* the ClosableIterator signature.
*/
public synchronized void returnPreparedSQLStatement(PreparedStatement ps) {
if (!CACHE_PREPARED_STATEMENTS) {
try {
ps.close();
} catch (SQLException e) {
logger.warn("Problem discarded prepared statement", e);
}
return;
}
List psl = m_cachedStmtInUse.get(ps);
if (psl != null) {
if (psl.size() >= MAX_PS_CACHE) {
try {
ps.close();
} catch (SQLException e) {
logger.warn("Problem discarded prepared statement", e);
}
} else {
psl.add(ps);
}
m_cachedStmtInUse.remove(ps);
} else {
throw new JenaException("Attempt to return unused prepared statement");
}
}
// /**
// * Execute a named pre-prepared SQL query statement taking a set of arguments and return
// * a set of results as an iterator (probably a subclass of ResultSetIterator. Returns null
// * if they query is an update (as opposed to an empty iterator for a true query which happens
// * to return no answers).
// *
// * Not sure this is a good design. Reducing this to a general interface leads to lots of clunky
// * wrapping and unwrapping of primitive types, coercions and lack of compile-time type checking.
// * On the other hand letting the clients do this themselves with direct jdbc calls leaves us up
// * to the mercy of the client to correctly use returnPreparedSQLStatement and on average seems
// * to lead to more duplication of boiler plate code. Currently the client can chose either approach.
// *
// * The calling arguments are passed in as an array.
// */
// public ResultSetIterator