001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 2007.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.repository.base;
007:
008: import java.io.File;
009: import java.io.FileInputStream;
010: import java.io.IOException;
011: import java.io.InputStream;
012: import java.io.Reader;
013: import java.net.URL;
014:
015: import org.slf4j.Logger;
016: import org.slf4j.LoggerFactory;
017:
018: import info.aduna.iteration.Iteration;
019:
020: import org.openrdf.OpenRDFUtil;
021: import org.openrdf.model.Resource;
022: import org.openrdf.model.Statement;
023: import org.openrdf.model.URI;
024: import org.openrdf.model.Value;
025: import org.openrdf.query.BooleanQuery;
026: import org.openrdf.query.GraphQuery;
027: import org.openrdf.query.MalformedQueryException;
028: import org.openrdf.query.Query;
029: import org.openrdf.query.QueryLanguage;
030: import org.openrdf.query.TupleQuery;
031: import org.openrdf.repository.Repository;
032: import org.openrdf.repository.RepositoryConnection;
033: import org.openrdf.repository.RepositoryException;
034: import org.openrdf.repository.RepositoryResult;
035: import org.openrdf.repository.util.RDFInserter;
036: import org.openrdf.rio.RDFFormat;
037: import org.openrdf.rio.RDFHandler;
038: import org.openrdf.rio.RDFHandlerException;
039: import org.openrdf.rio.RDFParseException;
040: import org.openrdf.rio.RDFParser;
041: import org.openrdf.rio.Rio;
042: import org.openrdf.rio.UnsupportedRDFormatException;
043:
044: /**
045: * Abstract class implementing most 'convenience' methods in the
046: * RepositoryConnection interface by transforming parameters and mapping the
047: * methods to the basic (abstractly declared) methods.
048: * <p>
049: * Open connections are automatically closed when being garbage collected. A
050: * warning message will be logged when the system property
051: * <tt>org.openrdf.repository.debug</tt> has been set to a non-<tt>null</tt>
052: * value.
053: *
054: * @author jeen
055: * @author Arjohn Kampman
056: */
057: public abstract class RepositoryConnectionBase implements
058: RepositoryConnection {
059:
060: /*
061: * Note: the following debugEnabled method are private so that they can be
062: * removed when open connections no longer block other connections and they
063: * can be closed silently (just like in JDBC).
064: */
065: private static boolean debugEnabled() {
066: return System.getProperty("org.openrdf.repository.debug") != null;
067: }
068:
069: protected final Logger logger = LoggerFactory.getLogger(this
070: .getClass());
071:
072: private final Repository repository;
073:
074: private boolean isOpen;
075:
076: private boolean autoCommit;
077:
078: /*
079: * Stores a stack trace that indicates where this connection as created if
080: * debugging is enabled.
081: */
082: private Throwable creatorTrace;
083:
084: protected RepositoryConnectionBase(Repository repository) {
085: this .repository = repository;
086: this .isOpen = true;
087: this .autoCommit = true;
088:
089: if (debugEnabled()) {
090: creatorTrace = new Throwable();
091: }
092: }
093:
094: public Repository getRepository() {
095: return repository;
096: }
097:
098: public boolean isOpen() throws RepositoryException {
099: return isOpen;
100: }
101:
102: public void close() throws RepositoryException {
103: isOpen = false;
104: }
105:
106: @Override
107: protected void finalize() throws Throwable {
108: try {
109: if (isOpen()) {
110: if (creatorTrace != null) {
111: logger
112: .warn(
113: "Closing connection due to garbage collection, connection was create in:",
114: creatorTrace);
115: }
116:
117: close();
118: }
119: } finally {
120: super .finalize();
121: }
122: }
123:
124: public Query prepareQuery(QueryLanguage ql, String query)
125: throws MalformedQueryException, RepositoryException {
126: return prepareQuery(ql, query, null);
127: }
128:
129: public TupleQuery prepareTupleQuery(QueryLanguage ql, String query)
130: throws MalformedQueryException, RepositoryException {
131: return prepareTupleQuery(ql, query, null);
132: }
133:
134: public GraphQuery prepareGraphQuery(QueryLanguage ql, String query)
135: throws MalformedQueryException, RepositoryException {
136: return prepareGraphQuery(ql, query, null);
137: }
138:
139: public BooleanQuery prepareBooleanQuery(QueryLanguage ql,
140: String query) throws MalformedQueryException,
141: RepositoryException {
142: return prepareBooleanQuery(ql, query, null);
143: }
144:
145: public boolean hasStatement(Resource subj, URI pred, Value obj,
146: boolean includeInferred, Resource... contexts)
147: throws RepositoryException {
148: RepositoryResult<Statement> stIter = getStatements(subj, pred,
149: obj, includeInferred, contexts);
150: try {
151: return stIter.hasNext();
152: } finally {
153: stIter.close();
154: }
155: }
156:
157: public boolean hasStatement(Statement st, boolean includeInferred,
158: Resource... contexts) throws RepositoryException {
159: return hasStatement(st.getSubject(), st.getPredicate(), st
160: .getObject(), includeInferred, contexts);
161: }
162:
163: public boolean isEmpty() throws RepositoryException {
164: return size() == 0;
165: }
166:
167: public void export(RDFHandler handler, Resource... contexts)
168: throws RepositoryException, RDFHandlerException {
169: exportStatements(null, null, null, false, handler, contexts);
170: }
171:
172: public void setAutoCommit(boolean autoCommit)
173: throws RepositoryException {
174: if (autoCommit == this .autoCommit) {
175: return;
176: }
177:
178: this .autoCommit = autoCommit;
179:
180: // if we are switching from non-autocommit to autocommit mode, commit any
181: // pending updates
182: if (autoCommit) {
183: commit();
184: }
185: }
186:
187: public boolean isAutoCommit() throws RepositoryException {
188: return autoCommit;
189: }
190:
191: /**
192: * Calls {@link #commit} when in auto-commit mode.
193: */
194: protected void autoCommit() throws RepositoryException {
195: if (isAutoCommit()) {
196: commit();
197: }
198: }
199:
200: public void add(File file, String baseURI, RDFFormat dataFormat,
201: Resource... contexts) throws IOException,
202: RDFParseException, RepositoryException {
203: if (baseURI == null) {
204: // default baseURI to file
205: baseURI = file.toURI().toString();
206: }
207:
208: InputStream in = new FileInputStream(file);
209:
210: try {
211: add(in, baseURI, dataFormat, contexts);
212: } finally {
213: in.close();
214: }
215: }
216:
217: public void add(URL url, String baseURI, RDFFormat dataFormat,
218: Resource... contexts) throws IOException,
219: RDFParseException, RepositoryException {
220: if (baseURI == null) {
221: baseURI = url.toExternalForm();
222: }
223:
224: InputStream in = url.openStream();
225:
226: try {
227: add(in, baseURI, dataFormat, contexts);
228: } finally {
229: in.close();
230: }
231: }
232:
233: public void add(InputStream in, String baseURI,
234: RDFFormat dataFormat, Resource... contexts)
235: throws IOException, RDFParseException, RepositoryException {
236: addInputStreamOrReader(in, baseURI, dataFormat, contexts);
237: }
238:
239: public void add(Reader reader, String baseURI,
240: RDFFormat dataFormat, Resource... contexts)
241: throws IOException, RDFParseException, RepositoryException {
242: addInputStreamOrReader(reader, baseURI, dataFormat, contexts);
243: }
244:
245: /**
246: * Adds the data that can be read from the supplied InputStream or Reader to
247: * this repository.
248: *
249: * @param inputStreamOrReader
250: * An {@link InputStream} or {@link Reader} containing RDF data that
251: * must be added to the repository.
252: * @param baseURI
253: * The base URI for the data.
254: * @param dataFormat
255: * The file format of the data.
256: * @param context
257: * The context to which the data should be added in case
258: * <tt>enforceContext</tt> is <tt>true</tt>. The value
259: * <tt>null</tt> indicates the null context.
260: * @throws IOException
261: * @throws UnsupportedRDFormatException
262: * @throws RDFParseException
263: * @throws RepositoryException
264: */
265: protected void addInputStreamOrReader(Object inputStreamOrReader,
266: String baseURI, RDFFormat dataFormat, Resource... contexts)
267: throws IOException, RDFParseException, RepositoryException {
268: OpenRDFUtil.verifyContextNotNull(contexts);
269:
270: RDFParser rdfParser = Rio.createParser(dataFormat,
271: getRepository().getValueFactory());
272:
273: rdfParser.setVerifyData(true);
274: rdfParser.setStopAtFirstError(true);
275: rdfParser
276: .setDatatypeHandling(RDFParser.DatatypeHandling.IGNORE);
277:
278: RDFInserter rdfInserter = new RDFInserter(this );
279: rdfInserter.enforceContext(contexts);
280: rdfParser.setRDFHandler(rdfInserter);
281:
282: boolean autoCommit = isAutoCommit();
283: setAutoCommit(false);
284:
285: try {
286: if (inputStreamOrReader instanceof InputStream) {
287: rdfParser.parse((InputStream) inputStreamOrReader,
288: baseURI);
289: } else if (inputStreamOrReader instanceof Reader) {
290: rdfParser.parse((Reader) inputStreamOrReader, baseURI);
291: } else {
292: throw new IllegalArgumentException(
293: "inputStreamOrReader must be an InputStream or a Reader, is a: "
294: + inputStreamOrReader.getClass());
295: }
296: } catch (RDFHandlerException e) {
297: if (autoCommit) {
298: rollback();
299: }
300: // RDFInserter only throws wrapped RepositoryExceptions
301: throw (RepositoryException) e.getCause();
302: } catch (RuntimeException e) {
303: if (autoCommit) {
304: rollback();
305: }
306: throw e;
307: } finally {
308: setAutoCommit(autoCommit);
309: }
310: }
311:
312: public void add(Iterable<? extends Statement> statements,
313: Resource... contexts) throws RepositoryException {
314: OpenRDFUtil.verifyContextNotNull(contexts);
315:
316: boolean autoCommit = isAutoCommit();
317: setAutoCommit(false);
318:
319: try {
320: for (Statement st : statements) {
321: addWithoutCommit(st, contexts);
322: }
323: } catch (RepositoryException e) {
324: if (autoCommit) {
325: rollback();
326: }
327: throw e;
328: } catch (RuntimeException e) {
329: if (autoCommit) {
330: rollback();
331: }
332: throw e;
333: } finally {
334: setAutoCommit(autoCommit);
335: }
336: }
337:
338: public <E extends Exception> void add(
339: Iteration<? extends Statement, E> statementIter,
340: Resource... contexts) throws RepositoryException, E {
341: OpenRDFUtil.verifyContextNotNull(contexts);
342:
343: boolean autoCommit = isAutoCommit();
344: setAutoCommit(false);
345:
346: try {
347: while (statementIter.hasNext()) {
348: addWithoutCommit(statementIter.next(), contexts);
349: }
350: } catch (RepositoryException e) {
351: if (autoCommit) {
352: rollback();
353: }
354: throw e;
355: } catch (RuntimeException e) {
356: if (autoCommit) {
357: rollback();
358: }
359: throw e;
360: } finally {
361: setAutoCommit(autoCommit);
362: }
363: }
364:
365: public void add(Statement st, Resource... contexts)
366: throws RepositoryException {
367: OpenRDFUtil.verifyContextNotNull(contexts);
368: addWithoutCommit(st, contexts);
369: autoCommit();
370: }
371:
372: public void add(Resource subject, URI predicate, Value object,
373: Resource... contexts) throws RepositoryException {
374: OpenRDFUtil.verifyContextNotNull(contexts);
375: addWithoutCommit(subject, predicate, object, contexts);
376: autoCommit();
377: }
378:
379: public void remove(Iterable<? extends Statement> statements,
380: Resource... contexts) throws RepositoryException {
381: OpenRDFUtil.verifyContextNotNull(contexts);
382:
383: boolean autoCommit = isAutoCommit();
384: setAutoCommit(false);
385:
386: try {
387: for (Statement st : statements) {
388: remove(st, contexts);
389: }
390: } catch (RepositoryException e) {
391: if (autoCommit) {
392: rollback();
393: }
394: throw e;
395: } catch (RuntimeException e) {
396: if (autoCommit) {
397: rollback();
398: }
399: throw e;
400: } finally {
401: setAutoCommit(autoCommit);
402: }
403: }
404:
405: public <E extends Exception> void remove(
406: Iteration<? extends Statement, E> statementIter,
407: Resource... contexts) throws RepositoryException, E {
408: boolean autoCommit = isAutoCommit();
409: setAutoCommit(false);
410:
411: try {
412: while (statementIter.hasNext()) {
413: remove(statementIter.next(), contexts);
414: }
415: } catch (RepositoryException e) {
416: if (autoCommit) {
417: rollback();
418: }
419: throw e;
420: } catch (RuntimeException e) {
421: if (autoCommit) {
422: rollback();
423: }
424: throw e;
425: } finally {
426: setAutoCommit(autoCommit);
427: }
428: }
429:
430: public void remove(Statement st, Resource... contexts)
431: throws RepositoryException {
432: OpenRDFUtil.verifyContextNotNull(contexts);
433: removeWithoutCommit(st, contexts);
434: autoCommit();
435: }
436:
437: public void remove(Resource subject, URI predicate, Value object,
438: Resource... contexts) throws RepositoryException {
439: OpenRDFUtil.verifyContextNotNull(contexts);
440: removeWithoutCommit(subject, predicate, object, contexts);
441: autoCommit();
442: }
443:
444: public void clear(Resource... contexts) throws RepositoryException {
445: remove(null, null, null, contexts);
446: }
447:
448: protected void addWithoutCommit(Statement st, Resource... contexts)
449: throws RepositoryException {
450: if (contexts.length == 0 && st.getContext() != null) {
451: contexts = new Resource[] { st.getContext() };
452: }
453:
454: addWithoutCommit(st.getSubject(), st.getPredicate(), st
455: .getObject(), contexts);
456: }
457:
458: protected abstract void addWithoutCommit(Resource subject,
459: URI predicate, Value object, Resource... contexts)
460: throws RepositoryException;
461:
462: protected void removeWithoutCommit(Statement st,
463: Resource... contexts) throws RepositoryException {
464: if (contexts.length == 0 && st.getContext() != null) {
465: contexts = new Resource[] { st.getContext() };
466: }
467:
468: removeWithoutCommit(st.getSubject(), st.getPredicate(), st
469: .getObject(), contexts);
470: }
471:
472: protected abstract void removeWithoutCommit(Resource subject,
473: URI predicate, Value object, Resource... contexts)
474: throws RepositoryException;
475: }
|