/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2008.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.sail.rdbms;
import static java.sql.Connection.TRANSACTION_READ_COMMITTED;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import info.aduna.concurrent.locks.ExclusiveLockManager;
import info.aduna.concurrent.locks.Lock;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.sail.SailConnection;
import org.openrdf.sail.helpers.DefaultSailChangedEvent;
import org.openrdf.sail.rdbms.evaluation.QueryBuilderFactory;
import org.openrdf.sail.rdbms.evaluation.RdbmsEvaluationFactory;
import org.openrdf.sail.rdbms.exceptions.RdbmsException;
import org.openrdf.sail.rdbms.managers.BNodeManager;
import org.openrdf.sail.rdbms.managers.HashManager;
import org.openrdf.sail.rdbms.managers.LiteralManager;
import org.openrdf.sail.rdbms.managers.NamespaceManager;
import org.openrdf.sail.rdbms.managers.PredicateManager;
import org.openrdf.sail.rdbms.managers.TransTableManager;
import org.openrdf.sail.rdbms.managers.TripleManager;
import org.openrdf.sail.rdbms.managers.TripleTableManager;
import org.openrdf.sail.rdbms.managers.UriManager;
import org.openrdf.sail.rdbms.optimizers.RdbmsQueryOptimizer;
import org.openrdf.sail.rdbms.optimizers.SelectQueryOptimizerFactory;
import org.openrdf.sail.rdbms.schema.BNodeTable;
import org.openrdf.sail.rdbms.schema.HashTable;
import org.openrdf.sail.rdbms.schema.IdSequence;
import org.openrdf.sail.rdbms.schema.IntegerIdSequence;
import org.openrdf.sail.rdbms.schema.LiteralTable;
import org.openrdf.sail.rdbms.schema.LongIdSequence;
import org.openrdf.sail.rdbms.schema.NamespacesTable;
import org.openrdf.sail.rdbms.schema.TableFactory;
import org.openrdf.sail.rdbms.schema.URITable;
import org.openrdf.sail.rdbms.schema.ValueTableFactory;
import org.openrdf.sail.rdbms.util.DatabaseLockManager;
import org.openrdf.sail.rdbms.util.Tracer;
import org.openrdf.store.StoreException;
/**
* Responsible to initialise and wire all components together that will be
* needed to satisfy any sail connection request.
*
* @author James Leigh
*/
public class RdbmsConnectionFactory {
private RdbmsStore sail;
private DataSource ds;
private String user;
private String password;
private Connection resourceInserts;
private Connection literalInserts;
private Connection hashLookups;
private Connection nsAndTableIndexes;
private NamespaceManager namespaces;
private TripleTableManager tripleTableManager;
private HashManager hashManager;
private RdbmsValueFactory vf;
private UriManager uriManager;
private BNodeManager bnodeManager;
private LiteralManager literalManager;
private PredicateManager predicateManager;
private int maxTripleTables;
private boolean triplesIndexed = true;
private boolean sequenced;
private HashTable hashTable;
private URITable uriTable;
private BNodeTable bnodeTable;
private LiteralTable literalTable;
private IdSequence ids;
private final ExclusiveLockManager lock = new ExclusiveLockManager();
private Lock databaseLock;
public void setSail(RdbmsStore sail) {
this.sail = sail;
}
public DataSource getDataSource() {
return ds;
}
public void setDataSource(DataSource ds) {
if (Tracer.isTraceEnabled()) {
this.ds = Tracer.traceDataSource(ds);
}
else {
this.ds = ds;
}
}
public void setDataSource(DataSource ds, String user, String password) {
setDataSource(ds);
this.user = user;
this.password = password;
}
public int getMaxNumberOfTripleTables() {
return maxTripleTables;
}
public void setMaxNumberOfTripleTables(int max) {
maxTripleTables = max;
}
public boolean isSequenced() {
return sequenced || hashManager != null;
}
public void setSequenced(boolean useSequence) {
this.sequenced = useSequence;
}
public boolean isTriplesIndexed() {
return triplesIndexed;
}
public void setTriplesIndexed(boolean triplesIndexed)
throws StoreException
{
this.triplesIndexed = triplesIndexed;
if (tripleTableManager != null) {
try {
if (triplesIndexed) {
tripleTableManager.createTripleIndexes();
}
else {
tripleTableManager.dropTripleIndexes();
}
}
catch (SQLException e) {
throw new RdbmsException(e);
}
}
}
public RdbmsValueFactory getValueFactory() {
return vf;
}
public void init()
throws StoreException
{
databaseLock = createDatabaseLock();
try {
nsAndTableIndexes = getConnection();
resourceInserts = getConnection();
literalInserts = getConnection();
nsAndTableIndexes.setAutoCommit(true);
resourceInserts.setAutoCommit(true);
literalInserts.setAutoCommit(true);
bnodeManager = new BNodeManager();
uriManager = new UriManager();
literalManager = new LiteralManager();
ValueTableFactory tables = createValueTableFactory();
tables.setSequenced(sequenced);
if (sequenced) {
ids = new IntegerIdSequence();
tables.setIdSequence(ids);
hashLookups = getConnection();
hashLookups.setAutoCommit(true);
hashManager = new HashManager();
hashTable = tables.createHashTable(hashLookups, hashManager.getQueue());
ids.setHashTable(hashTable);
ids.init();
hashManager.setHashTable(hashTable);
hashManager.setBNodeManager(bnodeManager);
hashManager.setLiteralManager(literalManager);
hashManager.setUriManager(uriManager);
hashManager.setIdSequence(ids);
hashManager.init();
}
else {
ids = new LongIdSequence();
ids.init();
tables.setIdSequence(ids);
}
namespaces = new NamespaceManager();
namespaces.setConnection(resourceInserts);
NamespacesTable nsTable = tables.createNamespacesTable(nsAndTableIndexes);
nsTable.initialize();
namespaces.setNamespacesTable(nsTable);
namespaces.initialize();
bnodeManager.setHashManager(hashManager);
bnodeManager.setIdSequence(ids);
uriManager.setHashManager(hashManager);
uriManager.setIdSequence(ids);
bnodeTable = tables.createBNodeTable(resourceInserts, bnodeManager.getQueue());
uriTable = tables.createURITable(resourceInserts, uriManager.getQueue());
literalManager.setHashManager(hashManager);
literalManager.setIdSequence(ids);
literalTable = tables.createLiteralTable(literalInserts, literalManager.getQueue());
literalTable.setIdSequence(ids);
vf = new RdbmsValueFactory();
vf.setDelegate(ValueFactoryImpl.getInstance());
vf.setIdSequence(ids);
uriManager.setUriTable(uriTable);
uriManager.init();
predicateManager = new PredicateManager();
predicateManager.setUriManager(uriManager);
tripleTableManager = new TripleTableManager(tables);
tripleTableManager.setConnection(nsAndTableIndexes);
tripleTableManager.setIdSequence(ids);
tripleTableManager.setBNodeManager(bnodeManager);
tripleTableManager.setUriManager(uriManager);
tripleTableManager.setLiteralManager(literalManager);
tripleTableManager.setHashManager(hashManager);
tripleTableManager.setPredicateManager(predicateManager);
tripleTableManager.setMaxNumberOfTripleTables(maxTripleTables);
tripleTableManager.setIndexingTriples(triplesIndexed);
tripleTableManager.initialize();
if (triplesIndexed) {
tripleTableManager.createTripleIndexes();
}
else {
tripleTableManager.dropTripleIndexes();
}
bnodeManager.setTable(bnodeTable);
bnodeManager.init();
vf.setBNodeManager(bnodeManager);
vf.setURIManager(uriManager);
literalManager.setTable(literalTable);
literalManager.init();
vf.setLiteralManager(literalManager);
vf.setPredicateManager(predicateManager);
}
catch (SQLException e) {
throw new RdbmsException(e);
}
}
public boolean isWritable()
throws StoreException
{
try {
return !nsAndTableIndexes.isReadOnly();
}
catch (SQLException e) {
throw new RdbmsException(e);
}
}
public URL getLocation()
throws StoreException
{
try {
String url = nsAndTableIndexes.getMetaData().getURL();
if (url == null) {
return null;
}
return new URL(url);
}
catch (SQLException e) {
throw new RdbmsException(e);
}
catch (MalformedURLException e) {
return null;
}
}
public SailConnection createConnection()
throws StoreException
{
try {
Connection db = getConnection();
db.setAutoCommit(true);
if (db.getTransactionIsolation() != TRANSACTION_READ_COMMITTED) {
db.setTransactionIsolation(TRANSACTION_READ_COMMITTED);
}
TripleManager tripleManager = new TripleManager();
RdbmsTripleRepository s = new RdbmsTripleRepository();
s.setTripleManager(tripleManager);
s.setValueFactory(vf);
s.setConnection(db);
s.setBNodeTable(bnodeTable);
s.setURITable(uriTable);
s.setLiteralTable(literalTable);
s.setIdSequence(ids);
DefaultSailChangedEvent sailChangedEvent = new DefaultSailChangedEvent(sail);
s.setSailChangedEvent(sailChangedEvent);
TableFactory tables = createTableFactory();
TransTableManager trans = createTransTableManager();
trans.setIdSequence(ids);
tripleManager.setTransTableManager(trans);
trans.setBatchQueue(tripleManager.getQueue());
trans.setSailChangedEvent(sailChangedEvent);
trans.setConnection(db);
trans.setTemporaryTableFactory(tables);
trans.setStatementsTable(tripleTableManager);
trans.setFromDummyTable(getFromDummyTable());
trans.initialize();
s.setTransaction(trans);
QueryBuilderFactory bfactory = createQueryBuilderFactory();
bfactory.setValueFactory(vf);
bfactory.setUsingHashTable(hashManager != null);
s.setQueryBuilderFactory(bfactory);
RdbmsConnection conn = new RdbmsConnection(sail, s);
conn.setNamespaces(namespaces);
RdbmsEvaluationFactory efactory = new RdbmsEvaluationFactory();
efactory.setQueryBuilderFactory(bfactory);
efactory.setRdbmsTripleRepository(s);
efactory.setIdSequence(ids);
conn.setRdbmsEvaluationFactory(efactory);
RdbmsQueryOptimizer optimizer = createOptimizer();
SelectQueryOptimizerFactory selectOptimizerFactory = createSelectQueryOptimizerFactory();
selectOptimizerFactory.setTransTableManager(trans);
selectOptimizerFactory.setValueFactory(vf);
selectOptimizerFactory.setIdSequence(ids);
optimizer.setSelectQueryOptimizerFactory(selectOptimizerFactory);
optimizer.setValueFactory(vf);
optimizer.setBnodeTable(bnodeTable);
optimizer.setUriTable(uriTable);
optimizer.setLiteralTable(literalTable);
optimizer.setHashTable(hashTable);
conn.setRdbmsQueryOptimizer(optimizer);
conn.setLockManager(lock);
return conn;
}
catch (SQLException e) {
throw new RdbmsException(e);
}
}
public void shutDown()
throws StoreException
{
try {
if (tripleTableManager != null) {
tripleTableManager.close();
}
if (uriManager != null) {
uriManager.close();
}
if (bnodeManager != null) {
bnodeManager.close();
}
if (literalManager != null) {
literalManager.close();
}
if (hashManager != null) {
hashManager.close();
}
if (resourceInserts != null) {
resourceInserts.close();
resourceInserts = null;
}
if (literalInserts != null) {
literalInserts.close();
literalInserts = null;
}
if (hashLookups != null) {
hashLookups.close();
hashLookups = null;
}
if (nsAndTableIndexes != null) {
nsAndTableIndexes.close();
nsAndTableIndexes = null;
}
}
catch (SQLException e) {
throw new RdbmsException(e);
}
finally {
if (databaseLock != null) {
databaseLock.release();
}
}
}
protected Lock createDatabaseLock()
throws StoreException
{
DatabaseLockManager manager;
manager = new DatabaseLockManager(ds, user, password);
if (manager.isDebugEnabled()) {
return manager.tryLock();
}
return manager.lockOrFail();
}
protected QueryBuilderFactory createQueryBuilderFactory() {
return new QueryBuilderFactory();
}
protected ValueTableFactory createValueTableFactory() {
return new ValueTableFactory(createTableFactory());
}
protected TableFactory createTableFactory() {
return new TableFactory();
}
protected TransTableManager createTransTableManager() {
return new TransTableManager();
}
protected RdbmsQueryOptimizer createOptimizer() {
return new RdbmsQueryOptimizer();
}
protected SelectQueryOptimizerFactory createSelectQueryOptimizerFactory() {
return new SelectQueryOptimizerFactory();
}
/**
* FROM DUAL
*
* @return from clause or empty string
*/
protected String getFromDummyTable() {
return "";
}
protected Connection getConnection()
throws SQLException
{
if (user == null) {
return ds.getConnection();
}
return ds.getConnection(user, password);
}
}