/* * Copyright Aduna (http://www.aduna-software.com/) (c) 2007. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.repository.base; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.net.URL; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import info.aduna.iteration.Iteration; import org.openrdf.OpenRDFUtil; import org.openrdf.model.Resource; import org.openrdf.model.Statement; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.query.BooleanQuery; import org.openrdf.query.GraphQuery; import org.openrdf.query.MalformedQueryException; import org.openrdf.query.Query; import org.openrdf.query.QueryLanguage; import org.openrdf.query.TupleQuery; import org.openrdf.repository.Repository; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.RepositoryResult; import org.openrdf.repository.util.RDFInserter; import org.openrdf.rio.RDFFormat; import org.openrdf.rio.RDFHandler; import org.openrdf.rio.RDFHandlerException; import org.openrdf.rio.RDFParseException; import org.openrdf.rio.RDFParser; import org.openrdf.rio.Rio; import org.openrdf.rio.UnsupportedRDFormatException; /** * Abstract class implementing most 'convenience' methods in the * RepositoryConnection interface by transforming parameters and mapping the * methods to the basic (abstractly declared) methods. * <p> * Open connections are automatically closed when being garbage collected. A * warning message will be logged when the system property * <tt>org.openrdf.repository.debug</tt> has been set to a non-<tt>null</tt> * value. * * @author jeen * @author Arjohn Kampman */ public abstract class RepositoryConnectionBase implements RepositoryConnection { /* * Note: the following debugEnabled method are private so that they can be * removed when open connections no longer block other connections and they * can be closed silently (just like in JDBC). */ private static boolean debugEnabled() { return System.getProperty("org.openrdf.repository.debug") != null; } protected final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Repository repository; private boolean isOpen; private boolean autoCommit; /* * Stores a stack trace that indicates where this connection as created if * debugging is enabled. */ private Throwable creatorTrace; protected RepositoryConnectionBase(Repository repository) { this.repository = repository; this.isOpen = true; this.autoCommit = true; if (debugEnabled()) { creatorTrace = new Throwable(); } } public Repository getRepository() { return repository; } public boolean isOpen() throws RepositoryException { return isOpen; } public void close() throws RepositoryException { isOpen = false; } @Override protected void finalize() throws Throwable { try { if (isOpen()) { if (creatorTrace != null) { logger.warn("Closing connection due to garbage collection, connection was create in:", creatorTrace); } close(); } } finally { super.finalize(); } } public Query prepareQuery(QueryLanguage ql, String query) throws MalformedQueryException, RepositoryException { return prepareQuery(ql, query, null); } public TupleQuery prepareTupleQuery(QueryLanguage ql, String query) throws MalformedQueryException, RepositoryException { return prepareTupleQuery(ql, query, null); } public GraphQuery prepareGraphQuery(QueryLanguage ql, String query) throws MalformedQueryException, RepositoryException { return prepareGraphQuery(ql, query, null); } public BooleanQuery prepareBooleanQuery(QueryLanguage ql, String query) throws MalformedQueryException, RepositoryException { return prepareBooleanQuery(ql, query, null); } public boolean hasStatement(Resource subj, URI pred, Value obj, boolean includeInferred, Resource... contexts) throws RepositoryException { RepositoryResult<Statement> stIter = getStatements(subj, pred, obj, includeInferred, contexts); try { return stIter.hasNext(); } finally { stIter.close(); } } public boolean hasStatement(Statement st, boolean includeInferred, Resource... contexts) throws RepositoryException { return hasStatement(st.getSubject(), st.getPredicate(), st.getObject(), includeInferred, contexts); } public boolean isEmpty() throws RepositoryException { return size() == 0; } public void export(RDFHandler handler, Resource... contexts) throws RepositoryException, RDFHandlerException { exportStatements(null, null, null, false, handler, contexts); } public void setAutoCommit(boolean autoCommit) throws RepositoryException { if (autoCommit == this.autoCommit) { return; } this.autoCommit = autoCommit; // if we are switching from non-autocommit to autocommit mode, commit any // pending updates if (autoCommit) { commit(); } } public boolean isAutoCommit() throws RepositoryException { return autoCommit; } /** * Calls {@link #commit} when in auto-commit mode. */ protected void autoCommit() throws RepositoryException { if (isAutoCommit()) { commit(); } } public void add(File file, String baseURI, RDFFormat dataFormat, Resource... contexts) throws IOException, RDFParseException, RepositoryException { if (baseURI == null) { // default baseURI to file baseURI = file.toURI().toString(); } InputStream in = new FileInputStream(file); try { add(in, baseURI, dataFormat, contexts); } finally { in.close(); } } public void add(URL url, String baseURI, RDFFormat dataFormat, Resource... contexts) throws IOException, RDFParseException, RepositoryException { if (baseURI == null) { baseURI = url.toExternalForm(); } InputStream in = url.openStream(); try { add(in, baseURI, dataFormat, contexts); } finally { in.close(); } } public void add(InputStream in, String baseURI, RDFFormat dataFormat, Resource... contexts) throws IOException, RDFParseException, RepositoryException { addInputStreamOrReader(in, baseURI, dataFormat, contexts); } public void add(Reader reader, String baseURI, RDFFormat dataFormat, Resource... contexts) throws IOException, RDFParseException, RepositoryException { addInputStreamOrReader(reader, baseURI, dataFormat, contexts); } /** * Adds the data that can be read from the supplied InputStream or Reader to * this repository. * * @param inputStreamOrReader * An {@link InputStream} or {@link Reader} containing RDF data that * must be added to the repository. * @param baseURI * The base URI for the data. * @param dataFormat * The file format of the data. * @param context * The context to which the data should be added in case * <tt>enforceContext</tt> is <tt>true</tt>. The value * <tt>null</tt> indicates the null context. * @throws IOException * @throws UnsupportedRDFormatException * @throws RDFParseException * @throws RepositoryException */ protected void addInputStreamOrReader(Object inputStreamOrReader, String baseURI, RDFFormat dataFormat, Resource... contexts) throws IOException, RDFParseException, RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); RDFParser rdfParser = Rio.createParser(dataFormat, getRepository().getValueFactory()); rdfParser.setVerifyData(true); rdfParser.setStopAtFirstError(true); rdfParser.setDatatypeHandling(RDFParser.DatatypeHandling.IGNORE); RDFInserter rdfInserter = new RDFInserter(this); rdfInserter.enforceContext(contexts); rdfParser.setRDFHandler(rdfInserter); boolean autoCommit = isAutoCommit(); setAutoCommit(false); try { if (inputStreamOrReader instanceof InputStream) { rdfParser.parse((InputStream)inputStreamOrReader, baseURI); } else if (inputStreamOrReader instanceof Reader) { rdfParser.parse((Reader)inputStreamOrReader, baseURI); } else { throw new IllegalArgumentException( "inputStreamOrReader must be an InputStream or a Reader, is a: " + inputStreamOrReader.getClass()); } } catch (RDFHandlerException e) { if (autoCommit) { rollback(); } // RDFInserter only throws wrapped RepositoryExceptions throw (RepositoryException)e.getCause(); } catch (RuntimeException e) { if (autoCommit) { rollback(); } throw e; } finally { setAutoCommit(autoCommit); } } public void add(Iterable<? extends Statement> statements, Resource... contexts) throws RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); boolean autoCommit = isAutoCommit(); setAutoCommit(false); try { for (Statement st : statements) { addWithoutCommit(st, contexts); } } catch (RepositoryException e) { if (autoCommit) { rollback(); } throw e; } catch (RuntimeException e) { if (autoCommit) { rollback(); } throw e; } finally { setAutoCommit(autoCommit); } } public <E extends Exception> void add(Iteration<? extends Statement, E> statementIter, Resource... contexts) throws RepositoryException, E { OpenRDFUtil.verifyContextNotNull(contexts); boolean autoCommit = isAutoCommit(); setAutoCommit(false); try { while (statementIter.hasNext()) { addWithoutCommit(statementIter.next(), contexts); } } catch (RepositoryException e) { if (autoCommit) { rollback(); } throw e; } catch (RuntimeException e) { if (autoCommit) { rollback(); } throw e; } finally { setAutoCommit(autoCommit); } } public void add(Statement st, Resource... contexts) throws RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); addWithoutCommit(st, contexts); autoCommit(); } public void add(Resource subject, URI predicate, Value object, Resource... contexts) throws RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); addWithoutCommit(subject, predicate, object, contexts); autoCommit(); } public void remove(Iterable<? extends Statement> statements, Resource... contexts) throws RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); boolean autoCommit = isAutoCommit(); setAutoCommit(false); try { for (Statement st : statements) { remove(st, contexts); } } catch (RepositoryException e) { if (autoCommit) { rollback(); } throw e; } catch (RuntimeException e) { if (autoCommit) { rollback(); } throw e; } finally { setAutoCommit(autoCommit); } } public <E extends Exception> void remove(Iteration<? extends Statement, E> statementIter, Resource... contexts) throws RepositoryException, E { boolean autoCommit = isAutoCommit(); setAutoCommit(false); try { while (statementIter.hasNext()) { remove(statementIter.next(), contexts); } } catch (RepositoryException e) { if (autoCommit) { rollback(); } throw e; } catch (RuntimeException e) { if (autoCommit) { rollback(); } throw e; } finally { setAutoCommit(autoCommit); } } public void remove(Statement st, Resource... contexts) throws RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); removeWithoutCommit(st, contexts); autoCommit(); } public void remove(Resource subject, URI predicate, Value object, Resource... contexts) throws RepositoryException { OpenRDFUtil.verifyContextNotNull(contexts); removeWithoutCommit(subject, predicate, object, contexts); autoCommit(); } public void clear(Resource... contexts) throws RepositoryException { remove(null, null, null, contexts); } protected void addWithoutCommit(Statement st, Resource... contexts) throws RepositoryException { if (contexts.length == 0 && st.getContext() != null) { contexts = new Resource[] { st.getContext() }; } addWithoutCommit(st.getSubject(), st.getPredicate(), st.getObject(), contexts); } protected abstract void addWithoutCommit(Resource subject, URI predicate, Value object, Resource... contexts) throws RepositoryException; protected void removeWithoutCommit(Statement st, Resource... contexts) throws RepositoryException { if (contexts.length == 0 && st.getContext() != null) { contexts = new Resource[] { st.getContext() }; } removeWithoutCommit(st.getSubject(), st.getPredicate(), st.getObject(), contexts); } protected abstract void removeWithoutCommit(Resource subject, URI predicate, Value object, Resource... contexts) throws RepositoryException; }