/******************************************************************************* * Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Distribution License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/org/documents/edl-v10.php. *******************************************************************************/ package org.eclipse.rdf4j.sail.model; import java.io.Closeable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Iterator; import java.util.Optional; import java.util.Set; import java.util.UUID; import org.eclipse.rdf4j.common.iteration.CloseableIteration; import org.eclipse.rdf4j.common.iteration.ExceptionConvertingIteration; import org.eclipse.rdf4j.common.iteration.Iteration; import org.eclipse.rdf4j.common.iteration.Iterations; import org.eclipse.rdf4j.common.iterator.CloseableIterationIterator; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Namespace; import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.impl.AbstractModel; import org.eclipse.rdf4j.model.impl.FilteredModel; import org.eclipse.rdf4j.model.impl.SimpleNamespace; import org.eclipse.rdf4j.model.util.ModelException; import org.eclipse.rdf4j.sail.SailConnection; import org.eclipse.rdf4j.sail.SailException; /** * Model implementation for a {@link org.eclipse.rdf4j.sail.SailConnection}. All * {@link org.eclipse.rdf4j.sail.SailException}s are wrapped in a {@link org.eclipse.rdf4j.model.util.ModelException}. * Not thread-safe. * * @author Mark * * @deprecated this feature is for internal use only: its existence, signature or behavior may change without warning * from one release to the next. */ public class SailModel extends AbstractModel { private static final long serialVersionUID = -2104886971549374410L; private transient SailConnection conn; private UUID connKey; private boolean includeInferred; public SailModel(SailConnection conn, boolean includeInferred) { this.conn = conn; this.includeInferred = includeInferred; } public void setConnection(SailConnection conn) { this.conn = conn; } @Override public Set<Namespace> getNamespaces() { Set<Namespace> namespaces; try { try (CloseableIteration<? extends Namespace, SailException> iter = conn.getNamespaces()) { namespaces = Iterations.asSet(conn.getNamespaces()); } } catch (SailException e) { throw new ModelException(e); } return namespaces; } @Override public Optional<Namespace> getNamespace(String prefix) { try { String name = conn.getNamespace(prefix); return (name != null) ? Optional.of(new SimpleNamespace(prefix, name)) : Optional.ofNullable(null); } catch (SailException e) { throw new ModelException(e); } } @Override public Namespace setNamespace(String prefix, String name) { try { conn.setNamespace(prefix, name); } catch (SailException e) { throw new ModelException(e); } return new SimpleNamespace(prefix, name); } @Override public void setNamespace(Namespace namespace) { try { conn.setNamespace(namespace.getPrefix(), namespace.getName()); } catch (SailException e) { throw new ModelException(e); } } @Override public Optional<Namespace> removeNamespace(String prefix) { Namespace namespace = getNamespace(prefix).orElse(null); if (namespace != null) { try { conn.removeNamespace(prefix); } catch (SailException e) { throw new ModelException(e); } } return Optional.ofNullable(namespace); } @Override public boolean contains(Resource subj, IRI pred, Value obj, Resource... contexts) { try { return conn.hasStatement(subj, pred, obj, includeInferred, contexts); } catch (SailException e) { throw new ModelException(e); } } @Override public boolean add(Resource subj, IRI pred, Value obj, Resource... contexts) { if (subj == null || pred == null || obj == null) { throw new UnsupportedOperationException("Incomplete statement"); } boolean exists = contains(subj, pred, obj, contexts); if (!exists) { try { conn.addStatement(subj, pred, obj, contexts); } catch (SailException e) { throw new ModelException(e); } } return !exists; } @Override public boolean remove(Resource subj, IRI pred, Value obj, Resource... contexts) { boolean exists = contains(subj, pred, obj, contexts); if (exists) { try { conn.removeStatements(subj, pred, obj, contexts); } catch (SailException e) { throw new ModelException(e); } } return exists; } @Override public boolean clear(Resource... contexts) { boolean exists = contains(null, null, null, contexts); if (exists) { try { conn.clear(contexts); } catch (SailException e) { throw new ModelException(e); } } return exists; } @Override public Model filter(Resource subj, IRI pred, Value obj, Resource... contexts) { return new FilteredModel(this, subj, pred, obj, contexts) { private static final long serialVersionUID = -3834026632361358191L; @Override public Iterator<Statement> iterator() { return SailModel.this.iterator(subj, pred, obj, contexts); } @Override protected void removeFilteredTermIteration(Iterator<Statement> iter, Resource subj, IRI pred, Value obj, Resource... contexts) { SailModel.this.removeTermIteration(iter, subj, pred, obj, contexts); } }; } @Override public void removeTermIteration(Iterator<Statement> iter, Resource subj, IRI pred, Value obj, Resource... contexts) { try { conn.removeStatements(subj, pred, obj, contexts); } catch (SailException e) { throw new ModelException(e); } } /** * The returned Iterator implements Closeable. If it is not exhausted then it should be explicitly closed. */ @Override public Iterator<Statement> iterator() { return iterator(null, null, null); } private Iterator<Statement> iterator(Resource subj, IRI pred, Value obj, Resource... contexts) { try { Iteration<? extends Statement, ?> iter = conn.getStatements(subj, pred, obj, includeInferred, contexts); return new CloseableIterationIterator<>( new ExceptionConvertingIteration<Statement, ModelException>(iter) { private Statement last; @Override public Statement next() { last = super.next(); return last; } @Override public void remove() { if (last == null) { throw new IllegalStateException("next() not yet called"); } SailModel.this.remove(last); last = null; } @Override protected ModelException convert(Exception e) { throw new ModelException(e); } }); } catch (SailException e) { throw new ModelException(e); } } @Override protected void closeIterator(Iterator<?> iter) { if (iter instanceof Closeable) { try { ((Closeable) iter).close(); } catch (IOException ioe) { throw new ModelException(ioe); } } else { super.closeIterator(iter); } } @Override public int size() { long lsize; if (!includeInferred) { try { lsize = conn.size(); } catch (SailException e) { throw new ModelException(e); } } else { lsize = 0L; Iterator<Statement> iter = iterator(); try { while (iter.hasNext()) { lsize++; iter.next(); } } finally { closeIterator(iter); } } return (lsize < Integer.MAX_VALUE) ? (int) lsize : Integer.MAX_VALUE; } private void writeObject(ObjectOutputStream out) throws IOException { this.connKey = NonSerializables.register(this.conn); out.defaultWriteObject(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.conn = SailConnection.class.cast(NonSerializables.get(this.connKey)); } }