View Javadoc
1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.commons.rdf.rdf4j.impl;
19  
20  import java.util.ConcurrentModificationException;
21  import java.util.Optional;
22  import java.util.UUID;
23  import java.util.stream.Stream;
24  
25  import org.apache.commons.rdf.api.BlankNodeOrIRI;
26  import org.apache.commons.rdf.api.Graph;
27  import org.apache.commons.rdf.api.IRI;
28  import org.apache.commons.rdf.api.Quad;
29  import org.apache.commons.rdf.api.RDFTerm;
30  import org.apache.commons.rdf.rdf4j.ClosableIterable;
31  import org.apache.commons.rdf.rdf4j.RDF4JDataset;
32  import org.apache.commons.rdf.rdf4j.RDF4JQuad;
33  import org.eclipse.rdf4j.common.iteration.Iterations;
34  import org.eclipse.rdf4j.model.Resource;
35  import org.eclipse.rdf4j.model.Statement;
36  import org.eclipse.rdf4j.model.Value;
37  import org.eclipse.rdf4j.repository.Repository;
38  import org.eclipse.rdf4j.repository.RepositoryConnection;
39  import org.eclipse.rdf4j.repository.RepositoryResult;
40  
41  class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset {
42  
43      RepositoryDatasetImpl(final Repository repository, final UUID salt, final boolean handleInitAndShutdown, final boolean includeInferred) {
44          super(repository, salt, handleInitAndShutdown, includeInferred);
45      }
46  
47      @Override
48      public void add(final Quad tripleLike) {
49          final Statement statement = rdf4jTermFactory.asStatement(tripleLike);
50          try (RepositoryConnection conn = getRepositoryConnection()) {
51              conn.add(statement);
52              conn.commit();
53          }
54      }
55  
56      @Override
57      public boolean contains(final Quad tripleLike) {
58          final Statement statement = rdf4jTermFactory.asStatement(tripleLike);
59          try (RepositoryConnection conn = getRepositoryConnection()) {
60              return conn.hasStatement(statement, includeInferred);
61          }
62      }
63  
64      @Override
65      public void remove(final Quad tripleLike) {
66          final Statement statement = rdf4jTermFactory.asStatement(tripleLike);
67          try (RepositoryConnection conn = getRepositoryConnection()) {
68              conn.remove(statement);
69              conn.commit();
70          }
71      }
72  
73      @Override
74      public void clear() {
75          try (RepositoryConnection conn = getRepositoryConnection()) {
76              conn.clear();
77              conn.commit();
78          }
79      }
80  
81      @Override
82      public long size() {
83          if (includeInferred) {
84              // We'll need to count them all
85              return stream().count();
86          }
87          // else: Ask directly
88          try (RepositoryConnection conn = getRepositoryConnection()) {
89              return conn.size();
90          }
91      }
92  
93      @Override
94      public void add(final BlankNodeOrIRI graphName, final BlankNodeOrIRI subject, final IRI predicate, final RDFTerm object) {
95          final Resource context = (Resource) rdf4jTermFactory.asValue(graphName);
96          final Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
97          final org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
98          final Value obj = rdf4jTermFactory.asValue(object);
99          try (RepositoryConnection conn = getRepositoryConnection()) {
100             conn.add(subj, pred, obj, context);
101             conn.commit();
102         }
103     }
104 
105     @Override
106     public boolean contains(final Optional<BlankNodeOrIRI> graphName, final BlankNodeOrIRI subject, final IRI predicate, final RDFTerm object) {
107         final Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
108         final org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
109         final Value obj = rdf4jTermFactory.asValue(object);
110         final Resource[] contexts = asContexts(graphName);
111         try (RepositoryConnection conn = getRepositoryConnection()) {
112             return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
113         }
114     }
115 
116     private Resource[] asContexts(final Optional<BlankNodeOrIRI> graphName) {
117         Resource[] contexts;
118         if (graphName == null) {
119             // no contexts == any contexts
120             contexts = new Resource[0];
121         } else {
122             final BlankNodeOrIRI g = graphName.orElse(null);
123             final Resource context = (Resource) rdf4jTermFactory.asValue(g);
124             contexts = new Resource[] { context };
125         }
126         return contexts;
127     }
128 
129     @Override
130     public void remove(final Optional<BlankNodeOrIRI> graphName, final BlankNodeOrIRI subject, final IRI predicate, final RDFTerm object) {
131         final Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
132         final org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
133         final Value obj = rdf4jTermFactory.asValue(object);
134         final Resource[] contexts = asContexts(graphName);
135 
136         try (RepositoryConnection conn = getRepositoryConnection()) {
137             conn.remove(subj, pred, obj, contexts);
138             conn.commit();
139         }
140     }
141 
142     @Override
143     public Stream<RDF4JQuad> stream() {
144         return stream(null, null, null, null);
145     }
146 
147     @Override
148     public Stream<RDF4JQuad> stream(final Optional<BlankNodeOrIRI> graphName, final BlankNodeOrIRI subject, final IRI predicate,
149             final RDFTerm object) {
150         final Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
151         final org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
152         final Value obj = rdf4jTermFactory.asValue(object);
153         final Resource[] contexts = asContexts(graphName);
154 
155         // NOTE: We can't do the usual try..with closing of the
156         // RepositoryConnection here as it will have to be closed outside
157         // by the user of the returned stream
158         final RepositoryConnection conn = getRepositoryConnection();
159         Stream<RDF4JQuad> stream = null;
160         try {
161             final RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contexts);
162             // NOTE: Iterations.stream should close RepositoryResult as long as
163             // our caller closes the stream
164             stream = Iterations.stream(statements).map(rdf4jTermFactory::asQuad);
165         } finally {
166             if (stream == null) {
167                 // Some exception before we made the stream, close connection
168                 // here
169                 conn.close();
170             }
171         }
172         // Make sure the RepositoryConnection is closed
173         return stream == null ? null : stream.onClose(conn::close);
174 
175     }
176 
177     @Override
178     public ClosableIterable<Quad> iterate() throws ConcurrentModificationException, IllegalStateException {
179         return iterate(null, null, null, null);
180     }
181 
182     @Override
183     public ClosableIterable<Quad> iterate(final Optional<BlankNodeOrIRI> graphName, final BlankNodeOrIRI subject, final IRI predicate,
184             final RDFTerm object) throws ConcurrentModificationException, IllegalStateException {
185         final Resource[] contexts = asContexts(graphName);
186         final Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
187         final org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
188         final Value obj = rdf4jTermFactory.asValue(object);
189         return new ConvertedStatements<>(this::getRepositoryConnection, rdf4jTermFactory::asQuad, subj, pred, obj,
190                 contexts);
191     }
192 
193     @Override
194     protected RDF4JQuad asTripleLike(final Statement s) {
195         return rdf4jTermFactory.asQuad(s);
196     }
197 
198     @Override
199     public Graph getGraph() {
200         // default context only
201         // NOTE: We carry over the 'salt' as the graph's BlankNode should be
202         // equal to our BlankNodes
203         return new RepositoryGraphImpl(repository, salt, false, includeInferred, (Resource) null);
204     }
205 
206     @Override
207     public Optional<Graph> getGraph(final BlankNodeOrIRI graphName) {
208         // NOTE: May be null to indicate default context
209         final Resource context = (Resource) rdf4jTermFactory.asValue(graphName);
210         // NOTE: We carry over the 'salt' as the graph's BlankNode should be
211         // equal to our BlankNodes
212         return Optional.of(new RepositoryGraphImpl(repository, salt, false, includeInferred, context));
213     }
214 
215     @Override
216     public Stream<BlankNodeOrIRI> getGraphNames() {
217        final RepositoryConnection conn = getRepositoryConnection();
218        final RepositoryResult<Resource> contexts = conn.getContextIDs();
219         return Iterations.stream(contexts).map(g -> (BlankNodeOrIRI) rdf4jTermFactory.asRDFTerm(g))
220                 .onClose(conn::close);
221     }
222 
223 }