You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2013/02/19 13:52:00 UTC
[38/52] [partial] code contribution,
initial import of relevant modules of LMF-3.0.0-SNAPSHOT based on
revision 4bf944319368 of the default branch at https://code.google.com/p/lmf/
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/IntArray.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/IntArray.java b/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/IntArray.java
new file mode 100644
index 0000000..8695fa4
--- /dev/null
+++ b/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/IntArray.java
@@ -0,0 +1,168 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.model.caching;
+
+import com.google.common.hash.HashCode;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+
+import java.nio.IntBuffer;
+import java.util.Arrays;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public final class IntArray implements Comparable<IntArray> {
+
+ private static HashFunction hashFunction = Hashing.goodFastHash(32);
+
+ private int[] data;
+
+ private HashCode goodHashCode;
+
+
+ public IntArray(int[] data) {
+ this.data = data;
+
+ Hasher hasher = hashFunction.newHasher();
+ for(int i : data) {
+ hasher.putInt(i);
+ }
+ goodHashCode = hasher.hash();
+ }
+
+ public static final IntArray createSPOCKey(Resource subject, URI property, Value object, Resource context){
+
+ // the cache key is generated by appending the bytes of the hashcodes of subject, property, object, context and inferred and
+ // storing them as a BigInteger; generating the cache key should thus be very efficient
+
+ int s = subject != null ? subject.hashCode() : Integer.MIN_VALUE;
+ int p = property != null ? property.hashCode() : Integer.MIN_VALUE;
+ int o = object != null ? object.hashCode() : Integer.MIN_VALUE;
+ int c = context != null ? context.hashCode() : Integer.MIN_VALUE;
+
+ IntBuffer bb = IntBuffer.allocate(4);
+ bb.put(s);
+ bb.put(p);
+ bb.put(o);
+ bb.put(c);
+
+ return new IntArray(bb.array());
+
+ }
+
+ public static final IntArray createSPOCMaxKey(Resource subject, URI property, Value object, URI context){
+
+ // the cache key is generated by appending the bytes of the hashcodes of subject, property, object, context and inferred and
+ // storing them as a BigInteger; generating the cache key should thus be very efficient
+
+ int s = subject != null ? subject.hashCode() : Integer.MAX_VALUE;
+ int p = property != null ? property.hashCode() : Integer.MAX_VALUE;
+ int o = object != null ? object.hashCode() : Integer.MAX_VALUE;
+ int c = context != null ? context.hashCode() : Integer.MAX_VALUE;
+
+ IntBuffer bb = IntBuffer.allocate(4);
+ bb.put(s);
+ bb.put(p);
+ bb.put(o);
+ bb.put(c);
+
+ return new IntArray(bb.array());
+
+ }
+
+ public static final IntArray createCSPOKey(Resource subject, URI property, Value object, Resource context){
+
+ // the cache key is generated by appending the bytes of the hashcodes of subject, property, object, context and inferred and
+ // storing them as a BigInteger; generating the cache key should thus be very efficient
+
+ int s = subject != null ? subject.hashCode() : Integer.MIN_VALUE;
+ int p = property != null ? property.hashCode() : Integer.MIN_VALUE;
+ int o = object != null ? object.hashCode() : Integer.MIN_VALUE;
+ int c = context != null ? context.hashCode() : Integer.MIN_VALUE;
+
+ IntBuffer bb = IntBuffer.allocate(4);
+ bb.put(c);
+ bb.put(s);
+ bb.put(p);
+ bb.put(o);
+
+ return new IntArray(bb.array());
+
+ }
+
+ public static final IntArray createCSPOMaxKey(Resource subject, URI property, Value object, URI context){
+
+ // the cache key is generated by appending the bytes of the hashcodes of subject, property, object, context and inferred and
+ // storing them as a BigInteger; generating the cache key should thus be very efficient
+
+ int s = subject != null ? subject.hashCode() : Integer.MAX_VALUE;
+ int p = property != null ? property.hashCode() : Integer.MAX_VALUE;
+ int o = object != null ? object.hashCode() : Integer.MAX_VALUE;
+ int c = context != null ? context.hashCode() : Integer.MAX_VALUE;
+
+ IntBuffer bb = IntBuffer.allocate(4);
+ bb.put(c);
+ bb.put(s);
+ bb.put(p);
+ bb.put(o);
+
+ return new IntArray(bb.array());
+
+ }
+
+ @Override
+ public String toString() {
+ return "IntArray{" +
+ "data=" + Arrays.toString(data) +
+ '}';
+ }
+
+ @Override
+ public int compareTo(IntArray o) {
+ for(int i=0; i < data.length && i < o.data.length; i++) {
+ if(data[i] < o.data[i]) {
+ return -1;
+ } else if(data[i] > o.data[i]) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IntArray intArray = (IntArray) o;
+
+ return Arrays.equals(data, intArray.data);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return goodHashCode.hashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/TripleTable.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/TripleTable.java b/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/TripleTable.java
new file mode 100644
index 0000000..41b450b
--- /dev/null
+++ b/kiwi/kiwi-tripletable/src/main/java/org/apache/marmotta/kiwi/model/caching/TripleTable.java
@@ -0,0 +1,469 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.model.caching;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Sets;
+import org.openrdf.model.Resource;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * A triple table that allows efficient in-memory operations over large collections of triples. This can be used as
+ * a simplified version of a Sesame in-memory repository (MemStore) using typical collection methods.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class TripleTable<Triple extends Statement> implements Set<Triple>, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private Set<Triple> data;
+
+ /**
+ * A set that orders triples orderd in a way that the subject is the most significant, while the context is the
+ * least significant property in the order. Can be used for efficient queries that involve either just a subject,
+ * a subject and a property, a subject, property and object or a subject, property, object and context
+ */
+ private NavigableMap<IntArray,Triple> indexSPOC;
+
+ /**
+ * A set that orders triples orderd in a way that the context is the most significant, while the object is the
+ * least significant property in the order. Can be used for efficient queries that involve either just a context,
+ * a context and a subject, a context, subject, and property
+ */
+ private NavigableMap<IntArray,Triple> indexCSPO;
+
+ public TripleTable() {
+ data = new HashSet<Triple>();
+ indexSPOC = new TreeMap<IntArray, Triple>();
+ indexCSPO = new TreeMap<IntArray, Triple>();
+ }
+
+
+ public TripleTable(Collection<Triple> triples) {
+ data = new HashSet<Triple>(triples.size());
+ indexSPOC = new TreeMap<IntArray, Triple>();
+ indexCSPO = new TreeMap<IntArray, Triple>();
+ addAll(triples);
+ }
+
+
+ /**
+ * Returns the number of elements in this set (its cardinality). If this
+ * set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
+ * <tt>Integer.MAX_VALUE</tt>.
+ *
+ * @return the number of elements in this set (its cardinality)
+ */
+ @Override
+ public int size() {
+ return data.size();
+ }
+
+ /**
+ * Returns <tt>true</tt> if this set contains no elements.
+ *
+ * @return <tt>true</tt> if this set contains no elements
+ */
+ @Override
+ public boolean isEmpty() {
+ return data.isEmpty();
+ }
+
+ /**
+ * Returns <tt>true</tt> if this set contains the specified element.
+ * More formally, returns <tt>true</tt> if and only if this set
+ * contains an element <tt>e</tt> such that
+ * <tt>(o==null ? e==null : o.equals(e))</tt>.
+ *
+ * @param o element whose presence in this set is to be tested
+ * @return <tt>true</tt> if this set contains the specified element
+ * @throws ClassCastException if the type of the specified element
+ * is incompatible with this set (optional)
+ * @throws NullPointerException if the specified element is null and this
+ * set does not permit null elements (optional)
+ */
+ @Override
+ public boolean contains(Object o) {
+ return data.contains(o);
+ }
+
+ /**
+ * Returns an iterator over the elements in this set. The elements are
+ * returned in no particular order (unless this set is an instance of some
+ * class that provides a guarantee).
+ *
+ * @return an iterator over the elements in this set
+ */
+ @Override
+ public Iterator<Triple> iterator() {
+ return data.iterator();
+ }
+
+ /**
+ * Returns an array containing all of the elements in this set.
+ * If this set makes any guarantees as to what order its elements
+ * are returned by its iterator, this method must return the
+ * elements in the same order.
+ *
+ * <p>The returned array will be "safe" in that no references to it
+ * are maintained by this set. (In other words, this method must
+ * allocate a new array even if this set is backed by an array).
+ * The caller is thus free to modify the returned array.
+ *
+ * <p>This method acts as bridge between array-based and collection-based
+ * APIs.
+ *
+ * @return an array containing all the elements in this set
+ */
+ @Override
+ public Object[] toArray() {
+ return data.toArray();
+ }
+
+ /**
+ * Returns an array containing all of the elements in this set; the
+ * runtime type of the returned array is that of the specified array.
+ * If the set fits in the specified array, it is returned therein.
+ * Otherwise, a new array is allocated with the runtime type of the
+ * specified array and the size of this set.
+ *
+ * <p>If this set fits in the specified array with room to spare
+ * (i.e., the array has more elements than this set), the element in
+ * the array immediately following the end of the set is set to
+ * <tt>null</tt>. (This is useful in determining the length of this
+ * set <i>only</i> if the caller knows that this set does not contain
+ * any null elements.)
+ *
+ * <p>If this set makes any guarantees as to what order its elements
+ * are returned by its iterator, this method must return the elements
+ * in the same order.
+ *
+ * <p>Like the {@link #toArray()} method, this method acts as bridge between
+ * array-based and collection-based APIs. Further, this method allows
+ * precise control over the runtime type of the output array, and may,
+ * under certain circumstances, be used to save allocation costs.
+ *
+ * <p>Suppose <tt>x</tt> is a set known to contain only strings.
+ * The following code can be used to dump the set into a newly allocated
+ * array of <tt>String</tt>:
+ *
+ * <pre>
+ * String[] y = x.toArray(new String[0]);</pre>
+ *
+ * Note that <tt>toArray(new Object[0])</tt> is identical in function to
+ * <tt>toArray()</tt>.
+ *
+ * @param a the array into which the elements of this set are to be
+ * stored, if it is big enough; otherwise, a new array of the same
+ * runtime type is allocated for this purpose.
+ * @return an array containing all the elements in this set
+ * @throws ArrayStoreException if the runtime type of the specified array
+ * is not a supertype of the runtime type of every element in this
+ * set
+ * @throws NullPointerException if the specified array is null
+ */
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return data.toArray(a);
+ }
+
+ /**
+ * Adds the specified element to this set if it is not already present
+ * (optional operation). More formally, adds the specified element
+ * <tt>e</tt> to this set if the set contains no element <tt>e2</tt>
+ * such that
+ * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
+ * If this set already contains the element, the call leaves the set
+ * unchanged and returns <tt>false</tt>. In combination with the
+ * restriction on constructors, this ensures that sets never contain
+ * duplicate elements.
+ *
+ * <p>The stipulation above does not imply that sets must accept all
+ * elements; sets may refuse to add any particular element, including
+ * <tt>null</tt>, and throw an exception, as described in the
+ * specification for {@link java.util.Collection#add Collection.add}.
+ * Individual set implementations should clearly document any
+ * restrictions on the elements that they may contain.
+ *
+ * @param triple element to be added to this set
+ * @return <tt>true</tt> if this set did not already contain the specified
+ * element
+ * @throws UnsupportedOperationException if the <tt>add</tt> operation
+ * is not supported by this set
+ * @throws ClassCastException if the class of the specified element
+ * prevents it from being added to this set
+ * @throws NullPointerException if the specified element is null and this
+ * set does not permit null elements
+ * @throws IllegalArgumentException if some property of the specified element
+ * prevents it from being added to this set
+ */
+ @Override
+ public boolean add(Triple triple) {
+ indexSPOC.put(IntArray.createSPOCKey(triple.getSubject(), triple.getPredicate(), triple.getObject(), triple.getContext()),triple);
+ indexCSPO.put(IntArray.createCSPOKey(triple.getSubject(), triple.getPredicate(), triple.getObject(), triple.getContext()),triple);
+ return data.add(triple);
+ }
+
+ /**
+ * Removes the specified element from this set if it is present
+ * (optional operation). More formally, removes an element <tt>e</tt>
+ * such that
+ * <tt>(o==null ? e==null : o.equals(e))</tt>, if
+ * this set contains such an element. Returns <tt>true</tt> if this set
+ * contained the element (or equivalently, if this set changed as a
+ * result of the call). (This set will not contain the element once the
+ * call returns.)
+ *
+ * @param o object to be removed from this set, if present
+ * @return <tt>true</tt> if this set contained the specified element
+ * @throws ClassCastException if the type of the specified element
+ * is incompatible with this set (optional)
+ * @throws NullPointerException if the specified element is null and this
+ * set does not permit null elements (optional)
+ * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+ * is not supported by this set
+ */
+ @Override
+ public boolean remove(Object o) {
+ if(o instanceof Statement) {
+ Statement triple = (Statement)o;
+ indexSPOC.remove(IntArray.createSPOCKey(triple.getSubject(), triple.getPredicate(), triple.getObject(), triple.getContext()));
+ indexCSPO.remove(IntArray.createCSPOKey(triple.getSubject(), triple.getPredicate(), triple.getObject(), triple.getContext()));
+ }
+ return data.remove(o);
+ }
+
+ /**
+ * Returns <tt>true</tt> if this set contains all of the elements of the
+ * specified collection. If the specified collection is also a set, this
+ * method returns <tt>true</tt> if it is a <i>subset</i> of this set.
+ *
+ * @param c collection to be checked for containment in this set
+ * @return <tt>true</tt> if this set contains all of the elements of the
+ * specified collection
+ * @throws ClassCastException if the types of one or more elements
+ * in the specified collection are incompatible with this
+ * set (optional)
+ * @throws NullPointerException if the specified collection contains one
+ * or more null elements and this set does not permit null
+ * elements (optional), or if the specified collection is null
+ * @see #contains(Object)
+ */
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return data.containsAll(c);
+ }
+
+ /**
+ * Adds all of the elements in the specified collection to this set if
+ * they're not already present (optional operation). If the specified
+ * collection is also a set, the <tt>addAll</tt> operation effectively
+ * modifies this set so that its value is the <i>union</i> of the two
+ * sets. The behavior of this operation is undefined if the specified
+ * collection is modified while the operation is in progress.
+ *
+ * @param c collection containing elements to be added to this set
+ * @return <tt>true</tt> if this set changed as a result of the call
+ *
+ * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+ * is not supported by this set
+ * @throws ClassCastException if the class of an element of the
+ * specified collection prevents it from being added to this set
+ * @throws NullPointerException if the specified collection contains one
+ * or more null elements and this set does not permit null
+ * elements, or if the specified collection is null
+ * @throws IllegalArgumentException if some property of an element of the
+ * specified collection prevents it from being added to this set
+ * @see #add(Object)
+ */
+ @Override
+ public boolean addAll(Collection<? extends Triple> c) {
+ boolean modified = false;
+ for(Triple t : c) {
+ modified = add(t) || modified;
+ }
+ return modified;
+ }
+
+ /**
+ * Retains only the elements in this set that are contained in the
+ * specified collection (optional operation). In other words, removes
+ * from this set all of its elements that are not contained in the
+ * specified collection. If the specified collection is also a set, this
+ * operation effectively modifies this set so that its value is the
+ * <i>intersection</i> of the two sets.
+ *
+ * @param c collection containing elements to be retained in this set
+ * @return <tt>true</tt> if this set changed as a result of the call
+ * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+ * is not supported by this set
+ * @throws ClassCastException if the class of an element of this set
+ * is incompatible with the specified collection (optional)
+ * @throws NullPointerException if this set contains a null element and the
+ * specified collection does not permit null elements (optional),
+ * or if the specified collection is null
+ * @see #remove(Object)
+ */
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ Iterator<Map.Entry<IntArray,Triple>> it = indexSPOC.entrySet().iterator();
+ while(it.hasNext()) {
+ if(!c.contains(it.next().getValue())) {
+ it.remove();
+ }
+ }
+ Iterator<Map.Entry<IntArray,Triple>> it2 = indexCSPO.entrySet().iterator();
+ while(it2.hasNext()) {
+ if(!c.contains(it2.next().getValue())) {
+ it2.remove();
+ }
+ }
+ return data.retainAll(c);
+ }
+
+ /**
+ * Removes from this set all of its elements that are contained in the
+ * specified collection (optional operation). If the specified
+ * collection is also a set, this operation effectively modifies this
+ * set so that its value is the <i>asymmetric set difference</i> of
+ * the two sets.
+ *
+ * @param c collection containing elements to be removed from this set
+ * @return <tt>true</tt> if this set changed as a result of the call
+ * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+ * is not supported by this set
+ * @throws ClassCastException if the class of an element of this set
+ * is incompatible with the specified collection (optional)
+ * @throws NullPointerException if this set contains a null element and the
+ * specified collection does not permit null elements (optional),
+ * or if the specified collection is null
+ * @see #remove(Object)
+ * @see #contains(Object)
+ */
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ boolean modified = false;
+ for(Object o : c) {
+ modified = remove(o) || modified;
+ }
+ return modified;
+ }
+
+ /**
+ * Removes all of the elements from this set (optional operation).
+ * The set will be empty after this call returns.
+ *
+ * @throws UnsupportedOperationException if the <tt>clear</tt> method
+ * is not supported by this set
+ */
+ @Override
+ public void clear() {
+ data.clear();
+ indexSPOC.clear();
+ indexCSPO.clear();
+ }
+
+ /**
+ * Return a subset of the triples matching the filter criteria. Arguments with null value are treated as wildcards.
+ *
+ * @param subject
+ * @param property
+ * @param object
+ * @param context
+ * @return
+ */
+ public Collection<Triple> listTriples(final Resource subject, final URI property, final Value object, final URI context) {
+ // in special cases we can make use of the index
+ if(subject != null && property != null && object != null && context != null) {
+ IntArray key = IntArray.createSPOCKey(subject, property, object, context);
+ Triple result = indexSPOC.get(key);
+ if(result != null) {
+ return Collections.singleton(result);
+ } else {
+ return Collections.emptyList();
+ }
+ } else if( (subject != null && property != null && object != null)
+ || (subject != null && property != null)
+ || subject != null) {
+ IntArray fromKey = IntArray.createSPOCKey(subject, property, object, context);
+ IntArray toKey = IntArray.createSPOCMaxKey(subject, property, object, context);
+
+ return indexSPOC.subMap(fromKey,true,toKey,true).values();
+ } else if( (context != null && subject != null && property != null)
+ || (context != null && subject != null)
+ || context != null) {
+ IntArray fromKey = IntArray.createCSPOKey(subject, property, object, context);
+ IntArray toKey = IntArray.createCSPOMaxKey(subject, property, object, context);
+
+ return indexCSPO.subMap(fromKey,true,toKey,true).values();
+ } else {
+ // in all other cases we need to iterate and filter :-(
+ Predicate<Statement> p = new Predicate<Statement>() {
+ @Override
+ public boolean apply(Statement triple) {
+ if(subject != null && !triple.getSubject().equals(subject)) {
+ return false;
+ }
+ if(property != null && !triple.getPredicate().equals(property)) {
+ return false;
+ }
+ if(object != null && !triple.getObject().equals(object)) {
+ return false;
+ }
+ if(context != null && !triple.getContext().equals(context)) {
+ return false;
+ }
+
+ return true;
+ }
+ };
+
+ return Sets.filter(data, p);
+ }
+ }
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ @SuppressWarnings("rawtypes")
+ TripleTable that = (TripleTable) o;
+
+ if (!data.equals(that.data)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return data.hashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.classpath
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.classpath b/kiwi/kiwi-versioning/.classpath
new file mode 100644
index 0000000..bf96ac0
--- /dev/null
+++ b/kiwi/kiwi-versioning/.classpath
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java"/>
+ <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+ <attributes>
+ <attribute name="org.eclipse.jst.component.nondependency" value=""/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.project
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.project b/kiwi/kiwi-versioning/.project
new file mode 100644
index 0000000..89f77a7
--- /dev/null
+++ b/kiwi/kiwi-versioning/.project
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>kiwi-versioning</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.settings/org.eclipse.core.resources.prefs
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.settings/org.eclipse.core.resources.prefs b/kiwi/kiwi-versioning/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..dc1b414
--- /dev/null
+++ b/kiwi/kiwi-versioning/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.settings/org.eclipse.jdt.core.prefs b/kiwi/kiwi-versioning/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..69c31cd
--- /dev/null
+++ b/kiwi/kiwi-versioning/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.settings/org.eclipse.m2e.core.prefs b/kiwi/kiwi-versioning/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/kiwi/kiwi-versioning/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.component
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.component b/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..21c1575
--- /dev/null
+++ b/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="kiwi-versioning">
+ <wb-resource deploy-path="/" source-path="/src/main/java"/>
+ <wb-resource deploy-path="/" source-path="/src/main/resources"/>
+ </wb-module>
+</project-modules>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.project.facet.core.xml
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.project.facet.core.xml b/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..c78d932
--- /dev/null
+++ b/kiwi/kiwi-versioning/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.6"/>
+ <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/pom.xml
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/pom.xml b/kiwi/kiwi-versioning/pom.xml
new file mode 100644
index 0000000..18040dd
--- /dev/null
+++ b/kiwi/kiwi-versioning/pom.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (c) 2013 The Apache Software Foundation
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>at.newmedialab.lmf</groupId>
+ <artifactId>kiwi-parent</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+
+ <artifactId>kiwi-versioning</artifactId>
+ <packaging>jar</packaging>
+
+ <name>KiWi Triplestore: Versioning</name>
+ <description>
+ Provides versioning functionality on top of the KiWi triplestore, i.e. allows keeping a log
+ of all changes carried out on the triple store as well as reverting to previous states.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>at.newmedialab.lmf</groupId>
+ <artifactId>kiwi-triplestore</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>at.newmedialab.lmf</groupId>
+ <artifactId>kiwi-transactions</artifactId>
+ </dependency>
+
+ <!-- Logging -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>log4j-over-slf4j</artifactId>
+ </dependency>
+
+ <!-- Sesame dependencies -->
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-sail-api</artifactId>
+ </dependency>
+
+ <!-- Utilities -->
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>at.newmedialab.sesame</groupId>
+ <artifactId>sesame-commons</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>at.newmedialab.sesame</groupId>
+ <artifactId>sesame-filter</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+
+
+ <!-- Testing -->
+ <dependency>
+ <artifactId>junit</artifactId>
+ <groupId>junit</groupId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>at.newmedialab.lmf</groupId>
+ <artifactId>kiwi-triplestore</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency> <!-- see http://www.dbunit.org/howto.html -->
+ <artifactId>dbunit</artifactId>
+ <groupId>org.dbunit</groupId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <artifactId>hamcrest-core</artifactId>
+ <groupId>org.hamcrest</groupId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <artifactId>hamcrest-library</artifactId>
+ <groupId>org.hamcrest</groupId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-rio-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-rio-rdfxml</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-queryparser-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-queryparser-sparql</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/api/VersioningSail.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/api/VersioningSail.java b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/api/VersioningSail.java
new file mode 100644
index 0000000..fdd74f1
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/api/VersioningSail.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.versioning.api;
+
+import org.apache.marmotta.kiwi.transactions.api.TransactionalSail;
+import org.apache.marmotta.kiwi.versioning.model.Version;
+import org.openrdf.model.Resource;
+import org.openrdf.repository.RepositoryResult;
+import org.openrdf.sail.SailConnection;
+import org.openrdf.sail.SailException;
+
+import java.util.Date;
+
+/**
+ * A Sesame SAIL with support for versioning of transaction data. Allows querying for the versions of a
+ * repository (see {@link Version}).
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public interface VersioningSail extends TransactionalSail {
+
+
+ /**
+ * List all versions of this repository.
+ *
+ * @return
+ */
+ public RepositoryResult<Version> listVersions() throws SailException;
+
+ /**
+ * List all versions of this repository between a start and end date.
+ *
+ * @return
+ */
+ public RepositoryResult<Version> listVersions(Date from, Date to) throws SailException;
+
+
+ /**
+ * Get a read-only snapshot of the repository at the given date. Returns a sail connection that
+ * can be used to access the triple data. Any attempts to modify the underlying data will throw
+ * a SailReadOnlyException.
+ *
+ * @param snapshotDate the date of which to take the snapshot; the snapshot will consist of all
+ * triples that have been created before or at the date and deleted after that date
+ * (or not deleted at all).
+ * @return a read-only sail connection to access the data of the triple store at the given date
+ */
+ public SailConnection getSnapshot(Date snapshotDate) throws SailException;
+
+ /**
+ * List all versions of this repository affecting the given resource as subject.
+ *
+ * @return
+ */
+ RepositoryResult<Version> listVersions(Resource r) throws SailException;
+
+ /**
+ * List all versions of this repository affecting the given resource as subject between a start and end date.
+ *
+ * @return
+ */
+ RepositoryResult<Version> listVersions(Resource r, Date from, Date to) throws SailException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/model/Version.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/model/Version.java b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/model/Version.java
new file mode 100644
index 0000000..5ed00aa
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/model/Version.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.versioning.model;
+
+import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
+import org.apache.marmotta.kiwi.transactions.model.TransactionData;
+
+/**
+ * In-memory representation of a KiWi version. Consists of a set of added triples, a set of removed triples,
+ * a commit date, and a database ID.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class Version extends TransactionData {
+
+ private Long id;
+
+ private KiWiResource creator;
+
+ public Version() {
+ super();
+ }
+
+ public Version(Long id) {
+ super();
+ this.id = id;
+ }
+
+ public Version(TransactionData data) {
+ this.addedTriples = data.getAddedTriples();
+ this.removedTriples = data.getRemovedTriples();
+ this.commitTime = data.getCommitTime();
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public KiWiResource getCreator() {
+ return creator;
+ }
+
+ public void setCreator(KiWiResource creator) {
+ this.creator = creator;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
new file mode 100644
index 0000000..169ddbf
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningConnection.java
@@ -0,0 +1,596 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.versioning.persistence;
+
+import info.aduna.iteration.CloseableIteration;
+import info.aduna.iteration.EmptyIteration;
+import info.aduna.iteration.ExceptionConvertingIteration;
+import org.apache.marmotta.kiwi.caching.KiWiCacheManager;
+import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
+import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
+import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
+import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
+import org.apache.marmotta.kiwi.persistence.KiWiConnection;
+import org.apache.marmotta.kiwi.persistence.KiWiDialect;
+import org.apache.marmotta.kiwi.persistence.util.ResultSetIteration;
+import org.apache.marmotta.kiwi.persistence.util.ResultTransformerFunction;
+import org.apache.marmotta.kiwi.versioning.model.Version;
+import org.openrdf.model.Statement;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.Date;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class KiWiVersioningConnection extends KiWiConnection {
+
+ private static Logger log = LoggerFactory.getLogger(KiWiVersioningConnection.class);
+
+ public KiWiVersioningConnection(Connection connection, KiWiDialect dialect, KiWiCacheManager cacheManager) throws SQLException {
+ super(connection, dialect, cacheManager);
+ }
+
+
+ /**
+ * Store a new version in the database. Will query for a new sequence ID for versions, insert a new row in the
+ * versions table, and then add join entries to the versions_added and versions_removed tables for each added
+ * and removed triple.
+ * <p/>
+ * Note that this method assumes the transaction data to be already consistent, i.e. a triple is not added and
+ * removed at the same time. No check for this situation is performed
+ *
+ * @param data
+ * @return
+ * @throws SQLException
+ */
+ public void storeVersion(Version data) throws SQLException {
+ if(data.getId() != null) {
+ log.warn("version {} already had a version ID, not persisting", data);
+ return;
+ }
+
+ // first create a new entry in the version table
+ data.setId(getNextSequence("seq.versions"));
+
+ PreparedStatement insertVersion = getPreparedStatement("store.version");
+ synchronized (insertVersion) {
+ insertVersion.setLong(1,data.getId());
+ if(data.getCreator() != null) {
+ insertVersion.setLong(2,data.getCreator().getId());
+ } else {
+ insertVersion.setObject(2, null);
+ }
+ insertVersion.setTimestamp(3, new Timestamp(data.getCommitTime().getTime()));
+ insertVersion.executeUpdate();
+ }
+
+ // then add join table entries for every added triple
+ PreparedStatement insertAdded = getPreparedStatement("store.version_added");
+ synchronized (insertAdded) {
+ insertAdded.clearParameters();
+ for(Statement added : data.getAddedTriples()) {
+ if(added instanceof KiWiTriple) {
+ insertAdded.setLong(1,data.getId());
+ insertAdded.setLong(2,((KiWiTriple) added).getId());
+ insertAdded.addBatch();
+ } else {
+ // maybe we should even throw an exception here
+ log.warn("cannot create version with statements that are not instances of KiWiTriple!");
+ }
+ }
+ insertAdded.executeBatch(); // if this is a performance issue, we could also run it every 1000 inserts or so
+ }
+
+ // then add join table entries for every removed triple
+ PreparedStatement insertRemoved = getPreparedStatement("store.version_removed");
+ synchronized (insertRemoved) {
+ insertRemoved.clearParameters();
+ for(Statement added : data.getRemovedTriples()) {
+ if(added instanceof KiWiTriple) {
+ insertRemoved.setLong(1,data.getId());
+ insertRemoved.setLong(2,((KiWiTriple) added).getId());
+ insertRemoved.addBatch();
+ } else {
+ // maybe we should even throw an exception here
+ log.warn("cannot create version with statements that are not instances of KiWiTriple!");
+ }
+ }
+ insertRemoved.executeBatch(); // if this is a performance issue, we could also run it every 1000 inserts or so
+ }
+
+ }
+
+ /**
+ * Retrieve a version by its id. If the version does not exist, returns null
+ *
+ * @param id
+ * @return
+ * @throws SQLException
+ */
+ public Version getVersion(Long id) throws SQLException {
+ PreparedStatement queryVersions = getPreparedStatement("load.version_by_id");
+ queryVersions.setLong(1,id);
+ queryVersions.setMaxRows(1);
+
+ ResultSet r = queryVersions.executeQuery();
+ try {
+ if(r.next()) {
+ return constructVersionFromDatabase(r);
+ } else {
+ return null;
+ }
+ } finally {
+ r.close();
+ }
+ }
+
+ /**
+ * Return the version that is the most recent version for a resource given a reference date. The method will either
+ * return the version that was current for the resource at the given date or return null in case such a version
+ * does not exist (e.g. before the resource was created).
+ *
+ * @param resource the resource for which to find a version
+ * @param date the reference date
+ * @return the latest version of the resource at the given date, or null if such a version does not exist
+ * @throws SQLException
+ */
+ public Version getLatestVersion(KiWiResource resource, Date date) throws SQLException {
+ PreparedStatement queryVersions = getPreparedStatement("load.versions_by_resource_latest");
+ synchronized (queryVersions) {
+ queryVersions.setLong(1, resource.getId());
+ queryVersions.setTimestamp(2, new Timestamp(date.getTime()));
+ queryVersions.setMaxRows(1);
+
+ ResultSet r = queryVersions.executeQuery();
+ try {
+ if(r.next()) {
+ return constructVersionFromDatabase(r);
+ } else {
+ return null;
+ }
+ } finally {
+ r.close();
+ }
+ }
+ }
+
+
+ /**
+ * List all versions in the database; operates directly on the result set, i.e. the iteration is carried out
+ * lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ public RepositoryResult<Version> listVersions() throws SQLException {
+
+ return new RepositoryResult<Version>(
+ new ExceptionConvertingIteration<Version, RepositoryException>(listVersionsInternal()) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException("database error while iterating over result set",e);
+ }
+ }
+
+ );
+ }
+
+
+ /**
+ * List all versions in the database; operates directly on the result set, i.e. the iteration is carried out
+ * lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ private CloseableIteration<Version, SQLException> listVersionsInternal() throws SQLException {
+ PreparedStatement queryVersions = getPreparedStatement("load.versions");
+
+ final ResultSet result = queryVersions.executeQuery();
+ return new ResultSetIteration<Version>(result, new ResultTransformerFunction<Version>() {
+ @Override
+ public Version apply(ResultSet row) throws SQLException {
+ return constructVersionFromDatabase(result);
+ }
+ });
+ }
+
+
+ /**
+ * List all versions in the database affecting the given resource as subject; operates directly on the result set,
+ * i.e. the iteration is carried out lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ public RepositoryResult<Version> listVersions(KiWiResource r) throws SQLException {
+
+ return new RepositoryResult<Version>(
+ new ExceptionConvertingIteration<Version, RepositoryException>(listVersionsInternal(r)) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException("database error while iterating over result set",e);
+ }
+ }
+
+ );
+ }
+
+ /**
+ * List all versions in the database affecting the given resource as subject; operates directly on the result set,
+ * i.e. the iteration is carried out lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ private CloseableIteration<Version, SQLException> listVersionsInternal(KiWiResource r) throws SQLException {
+ if(r.getId() == null) {
+ return new EmptyIteration<Version, SQLException>();
+ } else {
+ PreparedStatement queryVersions = getPreparedStatement("load.versions_by_resource");
+ queryVersions.setLong(1,r.getId());
+
+ final ResultSet result = queryVersions.executeQuery();
+ return new ResultSetIteration<Version>(result, new ResultTransformerFunction<Version>() {
+ @Override
+ public Version apply(ResultSet row) throws SQLException {
+ return constructVersionFromDatabase(result);
+ }
+ });
+ }
+
+ }
+
+
+
+ /**
+ * List all versions in the database; operates directly on the result set, i.e. the iteration is carried out
+ * lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ public RepositoryResult<Version> listVersions(final Date from, final Date to) throws SQLException {
+
+ return new RepositoryResult<Version>(
+ new ExceptionConvertingIteration<Version, RepositoryException>(listVersionsInternal(from, to)) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException("database error while iterating over result set",e);
+ }
+ }
+
+ );
+ }
+
+ /**
+ * List all versions in the database; operates directly on the result set, i.e. the iteration is carried out
+ * lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ private CloseableIteration<Version, SQLException> listVersionsInternal(Date from, Date to) throws SQLException {
+ PreparedStatement queryVersions = getPreparedStatement("load.version_between");
+ synchronized (queryVersions) {
+ queryVersions.clearParameters();
+ queryVersions.setTimestamp(1, new Timestamp(from.getTime()));
+ queryVersions.setTimestamp(2, new Timestamp(to.getTime()));
+
+ final ResultSet result = queryVersions.executeQuery();
+ return new ResultSetIteration<Version>(result, new ResultTransformerFunction<Version>() {
+ @Override
+ public Version apply(ResultSet row) throws SQLException {
+ return constructVersionFromDatabase(result);
+ }
+ });
+ }
+ }
+
+
+
+ /**
+ * List all versions in the database; operates directly on the result set, i.e. the iteration is carried out
+ * lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ public RepositoryResult<Version> listVersions(final KiWiResource r, final Date from, final Date to) throws SQLException {
+
+ return new RepositoryResult<Version>(
+ new ExceptionConvertingIteration<Version, RepositoryException>(listVersionsInternal(r, from, to)) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException("database error while iterating over result set",e);
+ }
+ }
+
+ );
+ }
+
+ /**
+ * List all versions in the database; operates directly on the result set, i.e. the iteration is carried out
+ * lazily and needs to be closed when iteration is completed.
+ *
+ * @return
+ * @throws SQLException
+ */
+ private CloseableIteration<Version, SQLException> listVersionsInternal(KiWiResource r, Date from, Date to) throws SQLException {
+ PreparedStatement queryVersions = getPreparedStatement("load.versions_by_resource_between");
+ synchronized (queryVersions) {
+ queryVersions.clearParameters();
+ if(r.getId() == null) {
+ return new EmptyIteration<Version, SQLException>();
+ } else {
+ queryVersions.setLong(1, r.getId());
+ queryVersions.setTimestamp(2, new Timestamp(from.getTime()));
+ queryVersions.setTimestamp(3, new Timestamp(to.getTime()));
+
+ final ResultSet result = queryVersions.executeQuery();
+ return new ResultSetIteration<Version>(result, new ResultTransformerFunction<Version>() {
+ @Override
+ public Version apply(ResultSet row) throws SQLException {
+ return constructVersionFromDatabase(result);
+ }
+ });
+ }
+ }
+ }
+
+
+ /**
+ * Construct a version from the database using the data contained in the result set row passed as argument. The method
+ * will load all added and removed triples in subsequent SQL queries.
+ * <p/>
+ * The method will not change the ResultSet iterator, only read its values, so it needs to be executed for each row separately.
+ *
+ * @param row
+ * @return
+ * @throws SQLException
+ */
+ protected Version constructVersionFromDatabase(ResultSet row) throws SQLException {
+ Version result = new Version(row.getLong("id"));
+ result.setCommitTime(new Date(row.getTimestamp("createdAt").getTime()));
+
+ if(row.getObject("creator") != null) {
+ result.setCreator((KiWiResource) loadNodeById(row.getLong("creator")));
+ }
+
+ // query the versions_added and versions_removed join tables to reconstruct the triple sets
+ PreparedStatement queryAdded = getPreparedStatement("load.versions_added");
+ synchronized (queryAdded) {
+ queryAdded.clearParameters();
+ queryAdded.setLong(1,result.getId());
+ ResultSet addedRow = queryAdded.executeQuery();
+ try {
+ while(addedRow.next()) {
+ result.addTriple(loadTripleById(addedRow.getLong("triple_id")));
+ }
+ } finally {
+ addedRow.close();
+ }
+ }
+
+ PreparedStatement queryRemoved = getPreparedStatement("load.versions_removed");
+ synchronized (queryRemoved) {
+ queryRemoved.clearParameters();
+ queryRemoved.setLong(1,result.getId());
+ ResultSet removedRow = queryRemoved.executeQuery();
+ try {
+ while(removedRow.next()) {
+ result.removeTriple(loadTripleById(removedRow.getLong("triple_id")));
+ }
+ } finally {
+ removedRow.close();
+ }
+ }
+
+ return result;
+ }
+
+
+
+ /**
+ * Return a Sesame RepositoryResult of statements according to the query pattern given in the arguments. Each of
+ * the parameters subject, predicate, object and context may be null, indicating a wildcard query. If the boolean
+ * parameter "inferred" is set to true, the result will also include inferred triples, if it is set to false only
+ * base triples.
+ * <p/>
+ * The RepositoryResult holds a direct connection to the database and needs to be closed properly, or otherwise
+ * the system might run out of resources. The returned RepositoryResult will try its best to clean up when the
+ * iteration has completed or the garbage collector calls the finalize() method, but this can take longer than
+ * necessary.
+ *
+ *
+ * @param subject the subject to query for, or null for a wildcard query
+ * @param predicate the predicate to query for, or null for a wildcard query
+ * @param object the object to query for, or null for a wildcard query
+ * @param context the context to query for, or null for a wildcard query
+ * @param inferred if true, the result will also contain triples inferred by the reasoner, if false not
+ * @return a new RepositoryResult with a direct connection to the database; the result should be properly closed
+ * by the caller
+ */
+ public RepositoryResult<Statement> listTriplesSnapshot(KiWiResource subject, KiWiUriResource predicate, KiWiNode object, KiWiResource context, boolean inferred, Date snapshotDate) throws SQLException {
+
+ return new RepositoryResult<Statement>(
+ new ExceptionConvertingIteration<Statement, RepositoryException>(listTriplesInternalSnapshot(subject, predicate, object, context, inferred, snapshotDate)) {
+ @Override
+ protected RepositoryException convert(Exception e) {
+ return new RepositoryException("database error while iterating over result set",e);
+ }
+ }
+
+ );
+ }
+
+ /**
+ * Internal implementation for actually carrying out the query. Returns a closable iteration that can be used
+ * in a repository result. The iteration is forward-only and does not allow removing result rows.
+ *
+ * @param subject the subject to query for, or null for a wildcard query
+ * @param predicate the predicate to query for, or null for a wildcard query
+ * @param object the object to query for, or null for a wildcard query
+ * @param context the context to query for, or null for a wildcard query
+ * @param inferred if true, the result will also contain triples inferred by the reasoner, if false not
+ * @return a ClosableIteration that wraps the database ResultSet; needs to be closed explicitly by the caller
+ * @throws SQLException
+ */
+ private CloseableIteration<Statement, SQLException> listTriplesInternalSnapshot(KiWiResource subject, KiWiUriResource predicate, KiWiNode object, KiWiResource context, boolean inferred, Date snapshotDate) throws SQLException {
+ // if one of the database ids is null, there will not be any database results, so we can return an empty result
+ if(subject != null && subject.getId() == null) {
+ return new EmptyIteration<Statement, SQLException>();
+ }
+ if(predicate != null && predicate.getId() == null) {
+ return new EmptyIteration<Statement, SQLException>();
+ }
+ if(object != null && object.getId() == null) {
+ return new EmptyIteration<Statement, SQLException>();
+ }
+ if(context != null && context.getId() == null) {
+ return new EmptyIteration<Statement, SQLException>();
+ }
+
+ // otherwise we need to create an appropriate SQL query and execute it, the repository result will be read-only
+ // and only allow forward iteration, so we can limit the query using the respective flags
+ PreparedStatement query = connection.prepareStatement(
+ constructTripleQuerySnapshot(subject, predicate, object, context, inferred, snapshotDate),
+ ResultSet.TYPE_FORWARD_ONLY,
+ ResultSet.CONCUR_READ_ONLY
+ );
+ query.clearParameters();
+
+ // set query parameters
+ query.setTimestamp(1, new Timestamp(snapshotDate.getTime()));
+ query.setTimestamp(2, new Timestamp(snapshotDate.getTime()));
+
+ int position = 3;
+ if(subject != null) {
+ query.setLong(position++, subject.getId());
+ }
+ if(predicate != null) {
+ query.setLong(position++, predicate.getId());
+ }
+ if(object != null) {
+ query.setLong(position++, object.getId());
+ }
+ if(context != null) {
+ query.setLong(position++, context.getId());
+ }
+
+ final ResultSet result = query.executeQuery();
+
+
+ return new ResultSetIteration<Statement>(result, true, new ResultTransformerFunction<Statement>() {
+ @Override
+ public Statement apply(ResultSet row) throws SQLException {
+ return constructTripleFromDatabase(result);
+ }
+ });
+ }
+
+ /**
+ * Construct the SQL query string from the query pattern passed as arguments
+ *
+ * @param subject the subject to query for, or null for a wildcard query
+ * @param predicate the predicate to query for, or null for a wildcard query
+ * @param object the object to query for, or null for a wildcard query
+ * @param context the context to query for, or null for a wildcard query
+ * @param inferred if true, the result will also contain triples inferred by the reasoner, if false not
+ * @return an SQL query string representing the triple pattern
+ */
+ protected String constructTripleQuerySnapshot(KiWiResource subject, KiWiUriResource predicate, KiWiNode object, KiWiResource context, boolean inferred, Date snapshotDate) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("SELECT id,subject,predicate,object,context,deleted,inferred,creator,createdAt,deletedAt FROM triples");
+ builder.append(" WHERE createdAt <= ? AND (deleted = false OR deletedAt > ?)");
+ if(subject != null) {
+ builder.append(" AND subject = ?");
+ }
+ if(predicate != null) {
+ builder.append(" AND predicate = ?");
+ }
+ if(object != null) {
+ builder.append(" AND object = ?");
+ }
+ if(context != null) {
+ builder.append(" AND context = ?");
+ }
+ if(!inferred) {
+ builder.append(" AND inferred = false");
+ }
+ return builder.toString();
+
+ }
+
+ /**
+ * Count all non-deleted triples in the triple store at the given snapshot date
+ * @return
+ * @throws SQLException
+ */
+ public long getSnapshotSize(Date snapshotDate) throws SQLException {
+ PreparedStatement querySize = getPreparedStatement("query.snapshot_size");
+ querySize.setTimestamp(1, new Timestamp(snapshotDate.getTime()));
+ querySize.setTimestamp(2, new Timestamp(snapshotDate.getTime()));
+ ResultSet result = querySize.executeQuery();
+ try {
+ if(result.next()) {
+ return result.getLong(1);
+ } else {
+ return 0;
+ }
+ } finally {
+ result.close();
+ }
+ }
+
+ /**
+ * Count all non-deleted triples in the triple store at the given snapshot date
+ * @return
+ * @throws SQLException
+ */
+ public long getSnapshotSize(KiWiResource context, Date snapshotDate) throws SQLException {
+ if(context.getId() == null) {
+ return 0;
+ };
+ PreparedStatement querySize = getPreparedStatement("query.snapshot_size_ctx");
+ querySize.setLong(1,context.getId());
+ querySize.setTimestamp(2, new Timestamp(snapshotDate.getTime()));
+ querySize.setTimestamp(3, new Timestamp(snapshotDate.getTime()));
+
+ ResultSet result = querySize.executeQuery();
+ try {
+ if(result.next()) {
+ return result.getLong(1);
+ } else {
+ return 0;
+ }
+ } finally {
+ result.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
new file mode 100644
index 0000000..98eb10f
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/persistence/KiWiVersioningPersistence.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.versioning.persistence;
+
+import org.apache.marmotta.kiwi.persistence.KiWiDialect;
+import org.apache.marmotta.kiwi.persistence.KiWiPersistence;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+
+/**
+ * This class handles all database access of the versioning component of the KiWi triple store. It provides
+ * methods for creating versions, deleting versions, listing versions, and accessing snapshots (following
+ * the Memento specification, http://mementoweb.org/)
+ * <p/>
+ * The KiWiVersioningPersistence makes use of a wrapped KiWiPersistence object passed as constructor argument.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class KiWiVersioningPersistence {
+
+ private static Logger log = LoggerFactory.getLogger(KiWiVersioningPersistence.class);
+
+
+ /**
+ * Get the parent persistence service to access the database
+ */
+ private KiWiPersistence persistence;
+
+
+ public KiWiVersioningPersistence(KiWiPersistence persistence) {
+ this.persistence = persistence;
+
+ persistence.addNodeTableDependency("versions", "creator");
+ persistence.addTripleTableDependency("versions_added","triple_id");
+ persistence.addTripleTableDependency("versions_removed","triple_id");
+ }
+
+ /**
+ * Initialise the database, creating or upgrading tables if they do not exist or are of the wrong version.
+ * This method must only be called after the initDatabase of the wrapped KiWiPersistence has been evaluated.
+ */
+ public void initDatabase() throws SQLException {
+ persistence.initDatabase("versioning", new String[] {"versions", "versions_added", "versions_removed"});
+ }
+
+ /**
+ * Drop the versioning tables; this method must be called before the dropDatabase method of the underlying
+ * KiWiPersistence is called.
+ *
+ * @throws SQLException
+ */
+ public void dropDatabase() throws SQLException {
+ persistence.dropDatabase("versioning");
+ }
+
+ /**
+ * Return a connection from the connection pool which already has the auto-commit disabled.
+ *
+ * @return a fresh JDBC connection from the connection pool
+ * @throws java.sql.SQLException in case a new connection could not be established
+ */
+ public KiWiVersioningConnection getConnection() throws SQLException {
+ return new KiWiVersioningConnection(persistence.getJDBCConnection(), persistence.getDialect(), persistence.getCacheManager());
+ }
+
+
+ public KiWiDialect getDialect() {
+ return persistence.getDialect();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepository.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepository.java b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepository.java
new file mode 100644
index 0000000..3469640
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepository.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.versioning.repository;
+
+import org.apache.marmotta.kiwi.versioning.model.Version;
+import org.apache.marmotta.kiwi.versioning.sail.KiWiVersioningSail;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.repository.sail.SailRepositoryConnection;
+import org.openrdf.sail.SailException;
+
+import java.util.Date;
+
+/**
+ * A wrapper around a KiWiVersioningSail that allows accessing snapshots using the Repository API instead of the
+ * SAIL API.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class SnapshotRepository extends SailRepository {
+
+ KiWiVersioningSail sail;
+
+ public SnapshotRepository(KiWiVersioningSail sail) {
+ super(sail);
+
+ this.sail = sail;
+ }
+
+ /**
+ * Get a read-only snapshot of the repository at the given date. Returns a repository connection that
+ * can be used to access the triple data. Any attempts to modify the underlying data will throw
+ * a SailReadOnlyException.
+ *
+ * @param snapshotDate the date of which to take the snapshot; the snapshot will consist of all
+ * triples that have been created before or at the date and deleted after that date
+ * (or not deleted at all).
+ * @return a read-only sail connection to access the data of the triple store at the given date
+ */
+ public SailRepositoryConnection getSnapshot(Date snapshotDate) throws RepositoryException {
+ try {
+ return new SnapshotRepositoryConnection(this, sail.getSnapshot(snapshotDate));
+ }
+ catch (SailException e) {
+ throw new RepositoryException(e);
+ }
+
+ }
+
+ /**
+ * List all versions of this repository.
+ *
+ * @return
+ */
+ public RepositoryResult<Version> listVersions() throws SailException {
+ return sail.listVersions();
+ }
+
+ /**
+ * List all versions of this repository between a start and end date.
+ *
+ * @return
+ */
+ public RepositoryResult<Version> listVersions(Date from, Date to) throws SailException {
+ return sail.listVersions(from, to);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepositoryConnection.java
----------------------------------------------------------------------
diff --git a/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepositoryConnection.java b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepositoryConnection.java
new file mode 100644
index 0000000..7de6136
--- /dev/null
+++ b/kiwi/kiwi-versioning/src/main/java/org/apache/marmotta/kiwi/versioning/repository/SnapshotRepositoryConnection.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.kiwi.versioning.repository;
+
+import org.apache.marmotta.kiwi.versioning.sail.KiWiSnapshotConnection;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.repository.sail.SailRepositoryConnection;
+
+/**
+ * A wrapper class for snapshot repository connections.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class SnapshotRepositoryConnection extends SailRepositoryConnection {
+
+ public SnapshotRepositoryConnection(SailRepository repository, KiWiSnapshotConnection sailConnection) {
+ super(repository, sailConnection);
+ }
+}