You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@clerezza.apache.org by re...@apache.org on 2015/03/22 23:04:52 UTC
[09/14] clerezza git commit: CLEREZZA-966: moved jena.tdb.storage
into the hierarchy
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProvider.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProvider.java b/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProvider.java
new file mode 100644
index 0000000..b8df417
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProvider.java
@@ -0,0 +1,717 @@
+package org.apache.clerezza.rdf.jena.tdb.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.EntityAlreadyExistsException;
+import org.apache.clerezza.rdf.core.access.EntityUndeletableException;
+import org.apache.clerezza.rdf.core.access.NoSuchEntityException;
+import org.apache.clerezza.rdf.core.access.QueryableTcProvider;
+import org.apache.clerezza.rdf.core.access.TcProvider;
+import org.apache.clerezza.rdf.core.access.WeightedTcProvider;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.jena.tdb.internals.ModelGraph;
+import org.apache.clerezza.rdf.jena.tdb.internals.Symbols;
+import org.apache.clerezza.rdf.jena.tdb.internals.UriRefSet;
+import org.apache.clerezza.rdf.ontologies.RDF;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.MapMaker;
+import com.hp.hpl.jena.query.Dataset;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.tdb.TDB;
+import com.hp.hpl.jena.tdb.TDBFactory;
+import org.apache.clerezza.rdf.core.access.TcManager;
+
+/**
+ * {@link WeightedTcProvider} implementation for Jena TDB that uses a single
+ * {@link TDBFactory#createDataset(String) Dataset} to store all created
+ * {@link Graph} and {@link MGraph} instances.<p>
+ * The {@link #TDB_DIR} is uses to configure the directory on the disc. It
+ * supports property substitution <code>'${property}'</code> based on properties defined
+ * in the {@link BundleContext#getProperty(String)} and
+ * {@link System#getProperty(String)}. This is to easily allow configurations
+ * such as <code>"${myHome}/myRdfStore"</code><p>
+ * The {@link #DEFAULT_GRAPH_NAME} property can be used to define the
+ * name of the Graph that exposes the {@link Dataset#getDefaultModel()} as
+ * both {@link TcProvider#getGraph(UriRef)} and {@link TcProvider#getMGraph(UriRef)}.
+ * This easily allows to access the union graph of the Jena TDB dataset.<p>
+ * This {@link TcProvider} {@link ConfigurationPolicy#REQUIRE requires} an
+ * configuration and uses the {@link Component#configurationFactory()
+ * configuration factory}. Therefore it will be bot active until a valid
+ * configuration is parsed to the {@link ConfigurationAdmin} service. However
+ * it supports multiple instances to be created.<p>
+ * Users that want to use multiple instances will need to use special filters
+ * to ensure that the correct instance is injected to components. As by default
+ * the instance with the highest {@link #WEIGHT} will be used by Clerezza
+ * to create instances. A good practice to filter for multiple instances is
+ * to add an additional user defined key to the configuration that can later
+ * be used for filtering. Such additional keys will be savely ignored by
+ * this implementation.<p>
+ *
+ * @author Rupert Westenthaler, MInto van der Sluis
+ *
+ */
+@Component(metatype=true, immediate=true,
+ configurationFactory=true, policy=ConfigurationPolicy.OPTIONAL)
+@Service({WeightedTcProvider.class, TcProvider.class, QueryableTcProvider.class})
+@Properties(value={
+ @Property(name=SingleTdbDatasetTcProvider.TDB_DIR),
+ @Property(name=SingleTdbDatasetTcProvider.DEFAULT_GRAPH_NAME),
+ @Property(name=SingleTdbDatasetTcProvider.SYNC_INTERVAL, intValue=SingleTdbDatasetTcProvider.DEFAULT_SYNC_INTERVAL),
+ @Property(name=SingleTdbDatasetTcProvider.WEIGHT, intValue=105),
+ @Property(name=TcManager.GENERAL_PURPOSE_TC, boolValue = true)
+})
+public class SingleTdbDatasetTcProvider extends BaseTdbTcProvider implements WeightedTcProvider {
+
+ public static final String TDB_DIR = "tdb-dir";
+ public static final String DEFAULT_GRAPH_NAME = "default-graph-name";
+ public static final String WEIGHT = "weight";
+ public static final String SYNC_INTERVAL = "sync-interval";
+ public static final String USE_GRAPH_NAME_SUFFIXES = "use-graph-name-suffixes";
+
+ public static final int DEFAULT_SYNC_INTERVAL = 6;
+ public static final int MIN_SYNC_INTERVAL = 3;
+
+ private final Logger log = LoggerFactory.getLogger(SingleTdbDatasetTcProvider.class);
+
+ private int weight;
+ private ModelGraph graphNameIndex;
+ private int syncInterval = DEFAULT_SYNC_INTERVAL;
+ private SyncThread syncThread;
+
+ private final ReadWriteLock datasetLock = new ReentrantReadWriteLock();;
+ private UriRef defaultGraphName;
+
+ // Ensure that models not yet garbage collected get properly synced.
+ private final ConcurrentMap<UriRef, ModelGraph> syncModels = new MapMaker().weakValues().makeMap();
+
+ /**
+ * This background thread ensures that changes to {@link Model}s are
+ * synchronized with the file system. Only {@link ModelGraph}s where
+ * <code>{@link ModelGraph#isReadWrite()} == true</code> are synced.<p>
+ * This is similar to the synchronize thread used by the {@link TdbTcProvider}.
+ * This thread is started during the
+ * {@link ScalableSingleTdbDatasetTcProvider#activate(ComponentContext) activation}
+ * ad the shutdown is requested during
+ * {@link ScalableSingleTdbDatasetTcProvider#deactivate(ComponentContext) deactivation}
+ */
+ class SyncThread extends Thread {
+ private boolean stopRequested = false;
+
+ @Override
+ public void run() {
+ while (!stopRequested) {
+ try {
+ Thread.sleep(syncInterval*1000);
+ } catch (InterruptedException ex) {
+ interrupt();
+ }
+ if (!stopRequested) {
+ datasetLock.writeLock().lock();
+ try {
+ for(ModelGraph mg : syncModels.values()){
+ if(mg.isReadWrite()){
+ mg.sync();
+ } //else we do not need to sync read-only models
+ }
+ } finally {
+ datasetLock.writeLock().unlock();
+ }
+ }
+ }
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+ }
+
+ /**
+ * Default constructor used by OSGI
+ */
+ public SingleTdbDatasetTcProvider(){}
+
+ /**
+ * Creates a TDB single dataset {@link TcProvider} based on the parsed
+ * configuration.<p>
+ * The following properties are supported:<ul>
+ * <li> {@link #TDB_DIR} (required): The directory used by Jena TDB. Property
+ * substitution "${property-name}" with {@link System#getProperties()} is
+ * supported.
+ * <li> {@link #DEFAULT_GRAPH_NAME}: The name ({@link UriRef}) of the
+ * {@link Graph} that exports the union graph. This graph allows to query
+ * triples in any named model managed by this {@link TcProvider}.
+ * <li> {@link #SYNC_INTERVAL}: The sync interval that
+ * is used to write changes in the graph to the file system. If missing
+ * the {@link #DEFAULT_SYNC_INTERVAL} is used. Values lower than
+ * {@link #MIN_SYNC_INTERVAL} are ignored
+ * <li>{@link #WEIGHT}: The weight of this {@link TcProvider}. If missing
+ * <code>0</code> is used as weight.
+ * </ul>
+ * <b>NOTE</b> Users need to call {@link #close()} to free up system
+ * resources when they are no longer need this instance.
+ * @param config The configuration
+ * @throws IOException the
+ * @throws ConfigurationException
+ */
+ public SingleTdbDatasetTcProvider(Dictionary<String,Object> config) throws ConfigurationException, IOException{
+ activate(null,config);
+ }
+ /**
+ * Activate method used by OSGI
+ * @param ctx
+ * @throws ConfigurationException
+ * @throws IOException
+ */
+ @Activate
+ @SuppressWarnings("unchecked")
+ protected void activate(ComponentContext ctx) throws ConfigurationException, IOException {
+ activate(ctx.getBundleContext(),ctx.getProperties());
+ }
+
+ /**
+ * Internally used for activation to support the instantiation via
+ * {@link #ScalableSingleTdbDatasetTcProvider(Dictionary)} - to be used outside
+ * an OSGI container.
+ * @param bc the BundleContext or <code>null</code> if activating outside
+ * an OSGI container. The BundleContext is just used to lookup properties
+ * for {@link #substituteProperty(String, BundleContext)}.
+ * @param config The configuration for this Instance. Note that {@link #TDB_DIR}
+ * is required to be present.
+ * @throws ConfigurationException if the parsed configuration is invalid
+ * @throws IOException on any error while creating/accessing the Jena TDB
+ * directory.
+ */
+ private void activate(BundleContext bc,Dictionary<String,Object> config) throws ConfigurationException, IOException {
+ log.info("Activating scalable single Dataset TDB provider");
+ Object value = config.get(WEIGHT);
+ if(value instanceof Number){
+ weight = ((Number)value).intValue();
+ } else if(value != null){
+ try {
+ weight = new BigDecimal(value.toString()).intValueExact();
+ } catch (RuntimeException e) {
+ throw new ConfigurationException(WEIGHT, "Unable to parse integer weight!", e);
+ }
+ } else { //weight not defined
+ weight = 0;
+ }
+ value = config.get(SYNC_INTERVAL);
+ if(value instanceof Number){
+ syncInterval = Math.max(((Number)value).intValue(),MIN_SYNC_INTERVAL);
+ } else if(value != null){
+ try {
+ syncInterval = Math.max(new BigDecimal(value.toString()).intValueExact(),MIN_SYNC_INTERVAL);
+ } catch (RuntimeException e) {
+ throw new ConfigurationException(SYNC_INTERVAL, "Unable to parse integer weight!", e);
+ }
+ } else { //sync interval not defined
+ syncInterval = DEFAULT_SYNC_INTERVAL;
+ }
+ value = config.get(TDB_DIR);
+ File dataDir;
+ if(value != null && !value.toString().isEmpty()){
+ dataDir = new File(substituteProperty(value.toString(),bc)).getAbsoluteFile();
+ } else {
+ value = config.get(Constants.SERVICE_PID);
+ if(value == null){
+ throw new ConfigurationException(TDB_DIR, "No Data Directory for "
+ + "the Jena TDB store parsed. Also unable to use the "
+ + "'service.pid' property as default because this property "
+ + "is not present in the parsed configuration.");
+ }
+ dataDir = bc.getDataFile("singleTdb"+File.separatorChar+value.toString());
+ log.info("No TDB directory parsed - use default '{}'",dataDir);
+ }
+ //parse the default graph name
+ value = config.get(DEFAULT_GRAPH_NAME);
+ if(value != null && !value.toString().isEmpty()){
+ try {
+ new URI(value.toString());
+ defaultGraphName = new UriRef(value.toString());
+ } catch (URISyntaxException e) {
+ throw new ConfigurationException(DEFAULT_GRAPH_NAME, "The parsed name '"
+ + value + "'for the default graph (union over all "
+ + "named graphs managed by this Jena TDB dataset) MUST BE "
+ + "an valid URI or NULL do deactivate this feature!",e);
+ }
+ } else {
+ defaultGraphName = null; //deactivate the default graph name
+ }
+
+ //validate the parsed directory!
+ if(!dataDir.exists()){
+ if(dataDir.mkdirs()){
+ log.info("Created Jena TDB data directory {}",dataDir);
+ } else {
+ throw new ConfigurationException(TDB_DIR, "Unable to create Jena TDB data directory '"+dataDir+"'!");
+ }
+ } else if(!dataDir.isDirectory()){
+ throw new ConfigurationException("tdb.dir", "Configured jena TDB data directory '"
+ + dataDir+"' already exists, but is not a Directory!");
+ } //else exists and is a directory ... nothing to do
+ TDB.getContext().set(TDB.symUnionDefaultGraph, true);
+ setDataset( TDBFactory.createDataset(dataDir.getAbsolutePath()) );
+ graphNameIndex = new ModelGraph(datasetLock, getDataset().getDefaultModel(),true);
+
+ // Remove existing default graph names from the index (if might have changed
+ // in the mean time).
+ removeDefaultGraphFromIndex();
+
+ //finally ensure the the defaultGraphName is not also used as a graph/mgraph name
+ if (defaultGraphName != null) {
+ if (isExistingGraphName(defaultGraphName)) {
+ throw new ConfigurationException(DEFAULT_GRAPH_NAME, "The configured default graph name '"
+ +defaultGraphName+"' is already used as a Graph or MGraph name!");
+ } else {
+ addToIndex( defaultGraphName, Symbols.Default );
+ addToIndex( defaultGraphName, Symbols.Graph );
+ }
+ }
+
+ syncThread = new SyncThread();
+ syncThread.setDaemon(true);
+ syncThread.setName("SyncDaemon for Jena TDB "+dataDir.getAbsolutePath());
+ syncThread.start();
+ }
+
+ /**
+ * call close in finalisation
+ */
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+
+ /**
+ * Closes this {@link TcProvider} instance and frees up all system resources.
+ * This method needs only to be called when using this TcProvider outside
+ * an OSGI environment.
+ */
+ public void close(){
+ deactivate(null);
+ }
+
+ /**
+ * Deactivates this component. Called by the OSGI environment if this
+ * component gets deactivated.
+ * @param ctx the ComponentContext. May be <code>null</code>
+ */
+ @Deactivate
+ protected void deactivate(ComponentContext ctx) {
+ if(syncThread != null){
+ syncThread.requestStop();
+ syncThread = null;
+ }
+ Dataset dataset = getDataset();
+ if(dataset != null){ //avoid NPE on multiple calls
+ datasetLock.writeLock().lock();
+ try {
+ for(ModelGraph mg : syncModels.values()){
+ mg.close(); //close also syncs!
+ }
+ syncModels.clear();
+
+ graphNameIndex.close();
+ graphNameIndex = null;
+
+ TDB.sync(dataset);
+ dataset.close();
+ setDataset(null);
+ } finally {
+ datasetLock.writeLock().unlock();
+ }
+ }
+ }
+
+ /**
+ * Internal method used to retrieve an existing Jena {@link ModelGraph}
+ * instance from {@link #syncModels} or initializes a new Jena TDB {@link Model}
+ * and Clerezza {@link Graph}s/{@link MGraph}s.
+ * @param name the name of the Graph to initialize/create
+ * @param readWrite if <code>true</code> a {@link MGraph} is initialized.
+ * Otherwise a {@link Graph} is created.
+ * @param create if this method is allowed to create an new {@link Model} or
+ * if an already existing model is initialized.
+ * @return the initialized {@link Model} and @link Graph} or {@link MGraph}.
+ * The returned instance will be also cached in {@link #syncModels}.
+ * @throws NoSuchEntityException If <code>create == false</code> and no
+ * {@link Model} for the parsed <code>name</code> exists.
+ */
+ private ModelGraph getModelGraph(UriRef name, boolean readWrite,boolean create) throws NoSuchEntityException {
+ ModelGraph modelGraph = null;
+ datasetLock.readLock().lock();
+ try {
+ if(readWrite) {
+ // Reuse existing model if not yet garbage collected.
+ modelGraph = syncModels.get(name);
+ }
+ if((modelGraph != null || isExistingGraphName(name)) && create){
+ throw new EntityAlreadyExistsException(name);
+ } else if(modelGraph == null){
+ String modelName = name.getUnicodeString();
+ modelGraph = new ModelGraph(datasetLock, name.equals(defaultGraphName) ?
+ getDataset().getNamedModel("urn:x-arq:UnionGraph") :
+ getDataset().getNamedModel(modelName),readWrite);
+ if(readWrite) {
+ // Keep track of readwrite model to be able to sync them.
+ this.syncModels.put(name, modelGraph);
+ }
+ }
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ return modelGraph;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#getGraph(org.apache.clerezza.rdf.core.UriRef)
+ */
+ @Override
+ public Graph getGraph(UriRef name) throws NoSuchEntityException {
+ if(name == null){
+ throw new IllegalArgumentException("The parsed Graph UriRef MUST NOT be NULL!");
+ }
+ datasetLock.readLock().lock();
+ try {
+ if (isExistingGraphName(name, Symbols.Graph) || name.equals(defaultGraphName)){
+ return getModelGraph(name,false,false).getGraph();
+ } else {
+ throw new NoSuchEntityException(name);
+ }
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#getMGraph(org.apache.clerezza.rdf.core.UriRef)
+ */
+ @Override
+ public MGraph getMGraph(UriRef name) throws NoSuchEntityException {
+ if(name == null){
+ throw new IllegalArgumentException("The parsed Graph UriRef MUST NOT be NULL!");
+ }
+ datasetLock.readLock().lock();
+ try {
+ if(isExistingGraphName(name, Symbols.MGraph)){
+ return getModelGraph(name,true,false).getMGraph();
+ } else {
+ throw new NoSuchEntityException(name);
+ }
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#getTriples(org.apache.clerezza.rdf.core.UriRef)
+ */
+ @Override
+ public TripleCollection getTriples(UriRef name) throws NoSuchEntityException {
+ if(name == null){
+ throw new IllegalArgumentException("The parsed Graph UriRef MUST NOT be NULL!");
+ }
+ datasetLock.readLock().lock();
+ try {
+ if(isExistingGraphName(name, Symbols.Graph) || name.equals(defaultGraphName)){
+ return getGraph(name);
+ } else if(isExistingGraphName(name, Symbols.MGraph)){
+ return getMGraph(name);
+ } else {
+ throw new NoSuchEntityException(name);
+ }
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#listGraphs()
+ */
+ @Override
+ public Set<UriRef> listGraphs() {
+ datasetLock.readLock().lock();
+ try {
+ return new HashSet(new UriRefSet( graphNameIndex, Symbols.Graph ));
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#listMGraphs()
+ */
+ @Override
+ public Set<UriRef> listMGraphs() {
+ datasetLock.readLock().lock();
+ try {
+ return new HashSet(new UriRefSet( graphNameIndex, Symbols.MGraph ));
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#listTripleCollections()
+ */
+ @Override
+ public Set<UriRef> listTripleCollections() {
+ datasetLock.readLock().lock();
+ try {
+ return new HashSet(new UriRefSet( graphNameIndex, null ));
+ } finally {
+ datasetLock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#createMGraph(org.apache.clerezza.rdf.core.UriRef)
+ */
+ @Override
+ public MGraph createMGraph(UriRef name) throws UnsupportedOperationException,
+ EntityAlreadyExistsException {
+ if(name == null){
+ throw new IllegalArgumentException("The parsed MGrpah name MUST NOT be NULL!");
+ }
+ datasetLock.writeLock().lock();
+ try {
+ if(isExistingGraphName(name)){
+ throw new EntityAlreadyExistsException(name);
+ }
+ MGraph graph = getModelGraph(name,true,true).getMGraph();
+ addToIndex( name, Symbols.MGraph);
+ return graph;
+ } finally {
+ datasetLock.writeLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#createGraph(org.apache.clerezza.rdf.core.UriRef, org.apache.clerezza.rdf.core.TripleCollection)
+ */
+ @Override
+ public Graph createGraph(UriRef name, TripleCollection triples) throws UnsupportedOperationException,
+ EntityAlreadyExistsException {
+ if(name == null){
+ throw new IllegalArgumentException("The parsed Grpah name MUST NOT be NULL!");
+ }
+ ModelGraph mg;
+ datasetLock.writeLock().lock();
+ try {
+ if(isExistingGraphName(name)){
+ throw new EntityAlreadyExistsException(name);
+ }
+ mg = getModelGraph(name,false,true);
+ addToIndex( name, Symbols.Graph);
+
+ //add the parsed data!
+ if(triples != null) { //load the initial and final set of triples
+ mg.getJenaAdapter().addAll(triples);
+ mg.sync();
+ }
+ } finally {
+ datasetLock.writeLock().unlock();
+ }
+ return mg.getGraph();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#deleteTripleCollection(org.apache.clerezza.rdf.core.UriRef)
+ */
+ @Override
+ public void deleteTripleCollection(UriRef name) throws UnsupportedOperationException,
+ NoSuchEntityException,
+ EntityUndeletableException {
+ if(name == null){
+ throw new IllegalArgumentException("The parsed MGrpah name MUST NOT be NULL!");
+ }
+ datasetLock.writeLock().lock();
+ try {
+ if(isExistingGraphName(name,Symbols.MGraph)){
+ ModelGraph mg = getModelGraph(name, true, false);
+ mg.delete();
+ removeFromIndex( name, Symbols.MGraph );
+ } else if(isExistingGraphName(name,Symbols.Graph)){
+ ModelGraph mg = getModelGraph(name, false, false);
+ mg.delete();
+ removeFromIndex( name, Symbols.Graph );
+ } else if (name.equals(defaultGraphName)){
+ throw new EntityUndeletableException(defaultGraphName);
+ }
+ //delete the graph from the initModels list
+ syncModels.remove(name);
+ } finally {
+ datasetLock.writeLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.TcProvider#getNames(org.apache.clerezza.rdf.core.Graph)
+ */
+ @Override
+ public Set<UriRef> getNames(Graph graph) {
+ //TODO: this method would require to compare the triples within the graph
+ // because an equals check will not work with BNodes.
+ Set<UriRef> graphNames = new HashSet<UriRef>();
+ for( Iterator<Triple> iterator = graphNameIndex.getMGraph().iterator(); iterator.hasNext(); ) {
+ Triple triple = iterator.next();
+ UriRef graphName = new UriRef(triple.getSubject().toString());
+ Graph currentGraph = getModelGraph(graphName, false, false).getGraph();
+ if(graph.equals(currentGraph)){
+ graphNames.add(graphName);
+ }
+ }
+ return graphNames;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.access.WeightedTcProvider#getWeight()
+ */
+ @Override
+ public int getWeight() {
+ return weight;
+ }
+
+ /**
+ * Substitutes ${property.name} with the values retrieved via <ul>
+ * <li> {@link BundleContext#getProperty(String)} or
+ * <li> {@link System#getProperty(String, String)} if the parsed
+ * {@link BundleContext} is <code>null</code>
+ * </ul>
+ * Substitutes with an empty string if the property is not present. If
+ * the substitution does not end with {@link File#separatorChar}, than it is
+ * appended to allow easily creating paths relative to root directory available
+ * as property regardless if the property includes/excludes the final
+ * separator char.
+ * <p>
+ * Nested substitutions are NOT supported. However multiple substitutions are supported.
+ * <p>
+ * If someone knows a default implementation feel free to replace!
+ *
+ * @param value
+ * the value to substitute
+ * @param bundleContext
+ * If not <code>null</code> the {@link BundleContext#getProperty(String)} is used instead of
+ * the {@link System#getProperty(String)}. By that it is possible to use OSGI only properties
+ * for substitution.
+ * @return the substituted value
+ */
+ private static String substituteProperty(String value, BundleContext bundleContext) {
+ int prevAt = 0;
+ int foundAt = 0;
+ StringBuilder substitution = new StringBuilder();
+ while ((foundAt = value.indexOf("${", prevAt)) >= prevAt) {
+ substitution.append(value.substring(prevAt, foundAt));
+ String propertyName = value.substring(foundAt + 2, value.indexOf('}', foundAt));
+ String propertyValue = bundleContext == null ? // if no bundleContext is available
+ System.getProperty(propertyName) : // use the System properties
+ bundleContext.getProperty(propertyName);
+ if(propertyValue != null) {
+ substitution.append(propertyValue);
+ if(propertyValue.charAt(propertyValue.length()-1) != File.separatorChar){
+ substitution.append(File.separatorChar);
+ }
+ } //else nothing to append
+ prevAt = foundAt + propertyName.length() + 3; // +3 -> "${}".length
+ }
+ substitution.append(value.substring(prevAt, value.length()));
+ return substitution.toString();
+ }
+
+ /**
+ * Checks whether the given graph name already exists as the specified resource (either graph or mgraph).
+ * @param graphName the graph name
+ * @param graphType the resource type
+ * @return true if a resource with the given name and type already exists, false otherwise.
+ */
+ private boolean isExistingGraphName(UriRef graphName, UriRef graphType) {
+ return graphNameIndex.getMGraph().filter(graphName, RDF.type, graphType).hasNext();
+ }
+
+ /**
+ * Checks whether the given graph name already exists as either a graph or mgraph.
+ * @param graphName the graph name
+ * @return true if a graph or mgraph with the given name already exists, false otherwise.
+ */
+ private boolean isExistingGraphName(UriRef graphName) {
+ return isExistingGraphName(graphName, null);
+ }
+
+ /**
+ * Adds a new graphname to the index of graphnames
+ * @param graphName name of the graph
+ * @param graphType resourcetype for the graph to add.
+ */
+ private void addToIndex(UriRef graphName, UriRef graphType) {
+ graphNameIndex.getMGraph().add(new TripleImpl(graphName, RDF.type, graphType));
+ graphNameIndex.sync();
+ }
+
+ /**
+ * Removes a graphanem from the index of graphnames
+ * @param graphName name of the graph to remove
+ * @param graphType resource type of the graph to remove.
+ */
+ private void removeFromIndex(UriRef graphName, UriRef graphType) {
+ MGraph index = graphNameIndex.getMGraph();
+ Iterator<Triple> triplesToRemove = index.filter(graphName, RDF.type, graphType);
+ for( ; triplesToRemove.hasNext(); ) {
+ triplesToRemove.next();
+ triplesToRemove.remove();
+ }
+ graphNameIndex.sync();
+ }
+
+ private void removeDefaultGraphFromIndex() {
+ MGraph index = graphNameIndex.getMGraph();
+ Iterator<Triple> triplesToRemove = index.filter(null, RDF.type, Symbols.Default);
+ for( ; triplesToRemove.hasNext(); ) {
+ Triple triple = triplesToRemove.next();
+ triplesToRemove.remove();
+ removeFromIndex( UriRef.class.cast(triple.getSubject()), Symbols.Graph );
+ }
+ graphNameIndex.sync();
+ }
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbTcProvider.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbTcProvider.java b/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbTcProvider.java
new file mode 100644
index 0000000..f8924fc
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/main/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbTcProvider.java
@@ -0,0 +1,434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.clerezza.rdf.jena.tdb.storage;
+
+import com.hp.hpl.jena.query.Dataset;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.tdb.TDB;
+import com.hp.hpl.jena.tdb.TDBFactory;
+import com.hp.hpl.jena.tdb.base.block.FileMode;
+import com.hp.hpl.jena.tdb.sys.SystemTDB;
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.logging.Level;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.EntityAlreadyExistsException;
+import org.apache.clerezza.rdf.core.access.EntityUndeletableException;
+import org.apache.clerezza.rdf.core.access.LockableMGraph;
+import org.apache.clerezza.rdf.core.access.LockableMGraphWrapper;
+import org.apache.clerezza.rdf.core.access.NoSuchEntityException;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.access.WeightedTcProvider;
+import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
+import org.apache.clerezza.rdf.core.impl.util.PrivilegedMGraphWrapper;
+import org.apache.clerezza.rdf.jena.storage.JenaGraphAdaptor;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+
+/**
+ * A {@link org.apache.clerezza.rdf.core.access.WeightedTcProvider} based on
+ * Jena TDB.
+ *
+ * @see <a href="http://jena.hpl.hp.com/wiki/TDB/JavaAPI">
+ * TDB/JavaAPI</a>
+ *
+ * @author reto, hasan
+ *
+ *
+ */
+@Component(metatype = true, immediate = true)
+@Service(WeightedTcProvider.class)
+@Properties({
+ @Property(name = "weight", intValue = 107),
+ @Property(name = TcManager.GENERAL_PURPOSE_TC, boolValue = true)})
+public class TdbTcProvider implements WeightedTcProvider {
+
+ static {
+ //not sure what the perfomance implication of this is
+ //it is only needed so that on windows the files of a dataset can be deleteds
+ SystemTDB.setFileMode(FileMode.direct);
+ }
+ @Property(intValue = 6, description = "Specifies the number of seconds to wait "
+ + "between synchronizations of the TDB datasets to the filesystem")
+ public static final String SYNC_INTERVAL = "sync-interval";
+ private int syncInterval = 6;
+ /**
+ * directory where all graphs are stored
+ */
+ private static final String DATA_PATH_NAME = "tdb-data/";
+ private String dataPathString = DATA_PATH_NAME;
+ private Map<UriRef, LockableMGraph> mGraphMap = new HashMap<UriRef, LockableMGraph>();
+ private Map<UriRef, Graph> graphMap = new HashMap<UriRef, Graph>();
+ private Map<File, com.hp.hpl.jena.graph.Graph> dir2JenaGraphMap = new HashMap<File, com.hp.hpl.jena.graph.Graph>();
+ private Map<File, Lock> dir2Lock = new HashMap<File, Lock>();
+ private final Map<File, Dataset> dir2Dataset = new HashMap<File, Dataset>();
+ private static final Logger log = LoggerFactory.getLogger(TdbTcProvider.class);
+ private int weight = 107;
+
+ class SyncThread extends Thread {
+
+ private boolean stopRequested = false;
+
+ @Override
+ public void run() {
+ while (!stopRequested) {
+ try {
+ Thread.sleep(syncInterval * 1000);
+ } catch (InterruptedException ex) {
+ interrupt();
+ }
+ if (!stopRequested) {
+ syncWithFileSystem();
+ }
+ }
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+ }
+ private SyncThread syncThread;
+
+ public TdbTcProvider() {
+ }
+
+ TdbTcProvider(File directory) {
+ dataPathString = directory.getAbsolutePath();
+ loadMGraphs();
+ loadGraphs();
+ }
+
+ public void activate(ComponentContext cCtx) {
+ log.info("Activating TDB provider");
+ if (cCtx != null) {
+ weight = (Integer) cCtx.getProperties().get("weight");
+ dataPathString = cCtx.getBundleContext().
+ getDataFile(DATA_PATH_NAME).getAbsolutePath();
+ syncInterval = Integer.parseInt(cCtx.getProperties().get(SYNC_INTERVAL).toString());
+ }
+ loadMGraphs();
+ loadGraphs();
+ syncThread = new SyncThread();
+ syncThread.start();
+ }
+
+ public void deactivate(ComponentContext cCtx) {
+ syncThread.requestStop();
+ syncThread = null;
+ for (com.hp.hpl.jena.graph.Graph jenaGraph : dir2JenaGraphMap.values()) {
+ jenaGraph.close();
+ }
+ synchronized (dir2Dataset) {
+ for (Dataset dataset : dir2Dataset.values()) {
+ dataset.close();
+ }
+ }
+ }
+
+ @Override
+ public int getWeight() {
+ return weight;
+ }
+
+ @Override
+ public Graph getGraph(UriRef name) throws NoSuchEntityException {
+ if (!graphMap.containsKey(name)) {
+ throw new NoSuchEntityException(name);
+ }
+ return graphMap.get(name);
+ }
+
+ @Override
+ public synchronized MGraph getMGraph(UriRef name) throws NoSuchEntityException {
+ if (!mGraphMap.containsKey(name)) {
+ throw new NoSuchEntityException(name);
+ }
+ return mGraphMap.get(name);
+ }
+
+ @Override
+ public TripleCollection getTriples(UriRef name) throws NoSuchEntityException {
+ try {
+ return getMGraph(name);
+ } catch (NoSuchEntityException e) {
+ return getGraph(name);
+ }
+ }
+
+ @Override
+ public synchronized MGraph createMGraph(UriRef name)
+ throws UnsupportedOperationException, EntityAlreadyExistsException {
+ File tcDir = getMGraphDir(name);
+ if (tcDir.exists()) {
+ throw new EntityAlreadyExistsException(name);
+ }
+ tcDir.mkdirs();
+ File otimizationIndicator = new File(tcDir, "fixed.opt");
+ try {
+ otimizationIndicator.createNewFile();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ LockableMGraph result = new LockableMGraphWrapper(getMGraph(tcDir));
+ dir2Lock.put(tcDir, result.getLock().writeLock());
+ mGraphMap.put(name, result);
+ return result;
+ }
+
+ @Override
+ public Graph createGraph(UriRef name, TripleCollection triples)
+ throws UnsupportedOperationException, EntityAlreadyExistsException {
+ File tcDir = getGraphDir(name);
+ if (tcDir.exists()) {
+ throw new EntityAlreadyExistsException(name);
+ }
+
+ if (triples == null) {
+ triples = new SimpleMGraph();
+ }
+ tcDir.mkdirs();
+ File otimizationIndicator = new File(tcDir, "fixed.opt");
+ try {
+ otimizationIndicator.createNewFile();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ MGraph mGraph = getMGraph(tcDir);
+ mGraph.addAll(triples);
+ Graph result = mGraph.getGraph();
+ TDB.sync(dir2Dataset.get(tcDir));
+ graphMap.put(name, result);
+ return result;
+ }
+
+ @Override
+ public void deleteTripleCollection(UriRef name)
+ throws UnsupportedOperationException, NoSuchEntityException,
+ EntityUndeletableException {
+ syncWithFileSystem();
+ if (deleteTcDir(getGraphDir(name))) {
+ graphMap.remove(name);
+ return;
+ }
+ if (deleteTcDir(getMGraphDir(name))) {
+ mGraphMap.remove(name);
+ return;
+ }
+ throw new NoSuchEntityException(name);
+ }
+
+ private boolean deleteTcDir(File tcDir) {
+ if (tcDir.exists()) {
+ dir2JenaGraphMap.get(tcDir).close();
+ dir2JenaGraphMap.remove(tcDir);
+ synchronized (dir2Dataset) {
+ dir2Dataset.get(tcDir).close();
+ dir2Dataset.remove(tcDir);
+ }
+ try {
+ delete(tcDir);
+ } catch (IOException ex) {
+ for (int i = 0; i < 10; i++) {
+ try {
+ System.gc();
+ delete(tcDir);
+ } catch (IOException ex1) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException ex2) {
+ Thread.currentThread().interrupt();
+ }
+ continue;
+ }
+ return true;
+ }
+ throw new RuntimeException(ex);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Cleans the content of the specified directory recursively.
+ *
+ * @param dir Abstract path denoting the directory to clean.
+ */
+ private static void cleanDirectory(File dir) throws IOException {
+ File[] files = dir.listFiles();
+ if (files != null && files.length > 0) {
+ for (File file : files) {
+ delete(file);
+ }
+ }
+ }
+
+ /**
+ * Deletes the specified file or directory.
+ *
+ * @param file Abstract path denoting the file or directory to clean.
+ */
+ protected static void delete(File file) throws IOException {
+ if (file.isDirectory()) {
+ cleanDirectory(file);
+ }
+ //better but only in java 7
+ //java.nio.file.Files.delete(file.toPath());
+ if (!file.delete()) {
+ throw new IOException("couldn't delete " + file.getAbsolutePath());
+ }
+ }
+
+ @Override
+ public Set<UriRef> getNames(Graph graph) {
+ //this could be done more efficiently with an index, could be done with
+ //a MultiBidiMap (BidiMap allowing multiple keys for the same value)
+ Set<UriRef> result = new HashSet<UriRef>();
+ for (UriRef name : listGraphs()) {
+ if (getGraph(name).equals(graph)) {
+ result.add(name);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public Set<UriRef> listTripleCollections() {
+ Set<UriRef> result = new HashSet<UriRef>();
+ result.addAll(listGraphs());
+ result.addAll(listMGraphs());
+ return result;
+ }
+
+ @Override
+ public Set<UriRef> listGraphs() {
+ return graphMap.keySet();
+ }
+
+ @Override
+ public Set<UriRef> listMGraphs() {
+ return mGraphMap.keySet();
+ }
+
+ private Graph getGraph(File tcDir) {
+ return getMGraph(tcDir).getGraph();
+ }
+
+ private File getGraphDir(UriRef name) {
+ File base = new File(dataPathString);
+ return getTcDir(new File(base, "graph"), name);
+ }
+
+ private MGraph getMGraph(File tcDir) {
+ Dataset dataset = TDBFactory.createDataset(tcDir.getAbsolutePath());
+ Model model = dataset.getDefaultModel();
+ //Model model = TDBFactory.createModel(tcDir.getAbsolutePath());
+ final com.hp.hpl.jena.graph.Graph jenaGraph = model.getGraph();
+ dir2JenaGraphMap.put(tcDir, jenaGraph);
+ //dataset.
+ synchronized (dir2Dataset) {
+ dir2Dataset.put(tcDir, dataset);
+ }
+ return new PrivilegedMGraphWrapper(new JenaGraphAdaptor(jenaGraph));
+ }
+
+ private File getMGraphDir(UriRef name) {
+ File base = new File(dataPathString);
+ return getTcDir(new File(base, "mgraph"), name);
+ }
+
+ private File getTcDir(File directory, UriRef name) {
+ try {
+ String subDirName = URLEncoder.encode(name.getUnicodeString(), "utf-8");
+ return new File(directory, subDirName);
+ } catch (UnsupportedEncodingException ex) {
+ throw new RuntimeException("utf-8 not supported", ex);
+ }
+ }
+
+ private void loadGraphs() {
+ File graphsDir = new File(new File(dataPathString), "graph");
+ if (graphsDir.exists()) {
+ for (String graphDirName : graphsDir.list()) {
+ try {
+ UriRef uri = new UriRef(URLDecoder.decode(graphDirName, "utf-8"));
+ log.info("loading: " + graphDirName);
+ graphMap.put(uri, getGraph(new File(graphsDir, graphDirName)));
+ } catch (UnsupportedEncodingException ex) {
+ throw new RuntimeException("utf-8 not supported", ex);
+ } catch (Exception e) {
+ log.error("Could not load tdb graph in " + graphDirName, e);
+ }
+ }
+ }
+ }
+
+ private void loadMGraphs() {
+ File mGraphsDir = new File(new File(dataPathString), "mgraph");
+ if (mGraphsDir.exists()) {
+ for (String mGraphDirName : mGraphsDir.list()) {
+ try {
+ UriRef uri = new UriRef(URLDecoder.decode(mGraphDirName, "utf-8"));
+ log.info("loading: " + mGraphDirName);
+ final File tcDir = new File(mGraphsDir, mGraphDirName);
+ final LockableMGraphWrapper lockableMGraph = new LockableMGraphWrapper(getMGraph(tcDir));
+ mGraphMap.put(uri, lockableMGraph);
+ dir2Lock.put(tcDir, lockableMGraph.getLock().writeLock());
+ } catch (UnsupportedEncodingException ex) {
+ throw new RuntimeException("utf-8 not supported", ex);
+ } catch (Exception e) {
+ log.error("Could not load tdb graph in " + mGraphDirName, e);
+ }
+ }
+ }
+ }
+
+ public void syncWithFileSystem() {
+ synchronized (dir2Dataset) {
+ for (Map.Entry<File, Dataset> entry : dir2Dataset.entrySet()) {
+ Lock l = dir2Lock.get(entry.getKey());
+ if (l == null) {
+ return;
+ }
+ l.lock();
+ try {
+ TDB.sync(entry.getValue());
+ } finally {
+ l.unlock();
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/main/resources/META-INF/services/org.apache.clerezza.rdf.core.access.WeightedTcProvider
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/main/resources/META-INF/services/org.apache.clerezza.rdf.core.access.WeightedTcProvider b/rdf/jena/tdb.storage/src/main/resources/META-INF/services/org.apache.clerezza.rdf.core.access.WeightedTcProvider
new file mode 100644
index 0000000..5dbaf81
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/main/resources/META-INF/services/org.apache.clerezza.rdf.core.access.WeightedTcProvider
@@ -0,0 +1 @@
+org.apache.clerezza.rdf.jena.tdb.storage.TdbTcProvider
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/main/resources/OSGI-INF/metatype/metatype.properties
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/main/resources/OSGI-INF/metatype/metatype.properties b/rdf/jena/tdb.storage/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..b2488eb
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# Deactivate properties for component because those are not common for Apache Clerezza
+#org.apache.clerezza.rdf.jena.tdb.storage.SingleTdbDatasetTcProvider.name=Apache Stanbol Clerezza \
+#Single Jena TDB Provider
+#org.apache.clerezza.rdf.jena.tdb.storage.SingleTdbDatasetTcProvider.description=Tc Provider \
+#implementation that stores Clerezza TripleCollections as named graphs in a single Jena \
+#TDB store.
+
+#==============================================================
+#Properties and Options used to configure TDB dataset providers
+#==============================================================
+
+tdb-dir.name=Jena TDB directory
+tdb-dir.description= The directory for Jena the TDB database. This field \
+supports property substitution: '${property}' will be replaced with the value \
+of the 'property' available via the BundleContext or the system properties \
+(e.g. "${myHome}/myRdfStore")
+default-graph-name.name=Default Graph Name
+default-graph-name.description=The URI name of the default graph of the Jena \
+TDB database. Requests to the TcProvider with this URI will return an MGraph \
+that is the union over all the graphs managed by this TcProvider. If empty or \
+not defined the default graph is not exposed.
+weight.name=Weight
+weight.description=The weight of this TcProvider. Set to an low value (e.g. \
+value < 0) if you want to inject this instance by using a Filter. Set to a high \
+value (e.g. values > 1000) if you want this instance to be the default used by \
+Clerezza.
+sync-interval.name=Sync Interval
+sync-interval.description=The interval in seconds until changes are saved to \
+the file system. Sync will always occur if this provider is deactivated. However \
+on crashes all data since the last sync will be lost. The default is 6sec. \
+Higher values will reduce the overhead for periodically writing to the file \
+system.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedSingleTdbDatasetTest.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedSingleTdbDatasetTest.java b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedSingleTdbDatasetTest.java
new file mode 100644
index 0000000..ac0dc89
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedSingleTdbDatasetTest.java
@@ -0,0 +1,261 @@
+package org.apache.clerezza.rdf.jena.tdb.storage;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+*/
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+
+import org.apache.clerezza.rdf.core.BNode;
+import org.apache.clerezza.rdf.core.Literal;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.LockableMGraph;
+import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.osgi.service.cm.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.wymiwyg.commons.util.Util;
+
+
+public class MultiThreadedSingleTdbDatasetTest {
+
+ private Logger log = LoggerFactory.getLogger(MultiThreadedSingleTdbDatasetTest.class);
+
+ private static final String TEST_GRAPH_URI_PREFIX = "http://www.example.org/multiThreadTest";
+ private int[] graphNum = new int[]{0};
+ /**
+ * how many threads to start
+ */
+ private static final int TEST_THREAD_COUNT = 25;
+ private static final int VALIDATE_THREAD_COUNT = 2;
+ /**
+ * how many seconds to let them run
+ */
+ private static final int DELAY = 15;
+
+
+ protected final List<MGraph> mGraphs = new ArrayList<MGraph>();
+ protected final List<Set<Triple>> testTriplesList = new ArrayList<Set<Triple>>();
+ private Random random = new Random();
+
+ class TestThread extends Thread {
+
+ private boolean stopRequested;
+ private int addedTripleCount = 0;
+
+ public TestThread(final int id) {
+ setName("Test Thread "+id);
+ start();
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+
+ @Override
+ public void run() {
+ while (!stopRequested) {
+ float r;
+ synchronized (random) {
+ r = random.nextFloat();
+ }
+ MGraph graph;
+ Set<Triple> testTriples;
+ if(r > 0.995){
+ int num;
+ synchronized (graphNum) {
+ num = graphNum[0];
+ graphNum[0]++;
+ }
+ graph = provider.createMGraph(new UriRef(TEST_GRAPH_URI_PREFIX+num));
+ log.info(" ... creating the {}. Grpah", num+1);
+ testTriples = new HashSet<Triple>();
+ synchronized (mGraphs) {
+ mGraphs.add(graph);
+ testTriplesList.add(testTriples);
+ }
+ } else { //map the range [0..0.995] to the mGraphs
+ synchronized (mGraphs) {
+ int num = Math.round(r*(float)(mGraphs.size()-1)/0.995f);
+ graph = mGraphs.get(num);
+ testTriples = testTriplesList.get(num);
+ }
+ }
+ Literal randomLiteral = new PlainLiteralImpl(Util.createRandomString(22));
+ Triple triple = new TripleImpl(new BNode(), new UriRef("http://example.com/property"), randomLiteral);
+ graph.add(triple);
+ addedTripleCount++;
+ if ((addedTripleCount % 100) == 0) {
+ testTriples.add(triple);
+ }
+ }
+ }
+
+ public int getAddedTripleCount() {
+ return addedTripleCount;
+ }
+
+ }
+ /**
+ * Iterates over max. the first 10 triples of a Graph
+ * while acquiring a read lock on the graph.
+ * @author westei
+ *
+ */
+ class ValidatorThread extends Thread {
+
+ boolean stopRequested = false;
+
+ public ValidatorThread(int id) {
+ setName("Validator Thread "+id);
+ start();
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+
+ @Override
+ public void run() {
+ while (!stopRequested) {
+ float r;
+ synchronized (random) {
+ r = random.nextFloat();
+ }
+ int num = Math.round(r*(float)(mGraphs.size()-1));
+ LockableMGraph graph;
+ synchronized (mGraphs) {
+ graph = (LockableMGraph)mGraphs.get(num);
+ }
+ int elem = 0;
+ graph.getLock().readLock().lock();
+ try {
+ Iterator<Triple> it = graph.iterator();
+ while(it.hasNext() && elem < 10){
+ elem++;
+ it.next();
+ }
+ } finally {
+ graph.getLock().readLock().unlock();
+ }
+ //iterate inly every 200ms
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ //ignore
+ }
+ }
+ }
+
+
+
+ }
+
+
+
+ private static File tempFile;
+ private static Dictionary<String,Object> config;
+ private static SingleTdbDatasetTcProvider provider;
+ @BeforeClass
+ public static void setup() throws IOException, ConfigurationException {
+ tempFile = File.createTempFile("tdbdatasettest", null);
+ tempFile.delete();
+ tempFile.mkdirs();
+ config = new Hashtable<String,Object>();
+ config.put(SingleTdbDatasetTcProvider.TDB_DIR, tempFile.getAbsolutePath());
+ provider = new SingleTdbDatasetTcProvider(config);
+ }
+ @Before
+ public void createGraphs(){
+ mGraphs.add(provider.createMGraph(new UriRef(TEST_GRAPH_URI_PREFIX+graphNum[0])));
+ testTriplesList.add(new HashSet<Triple>());
+ graphNum[0]++;
+ mGraphs.add(provider.createMGraph(new UriRef(TEST_GRAPH_URI_PREFIX+graphNum[0])));
+ testTriplesList.add(new HashSet<Triple>());
+ graphNum[0]++;
+ }
+ @Test
+ public void perform() throws InterruptedException {
+ TestThread[] threads = new TestThread[TEST_THREAD_COUNT];
+ for (int i = 0; i < threads.length; i++) {
+ threads[i] = new TestThread(i);
+ }
+ ValidatorThread[] validators = new ValidatorThread[VALIDATE_THREAD_COUNT];
+ for(int i = 0; i < validators.length; i++) {
+ validators [i] = new ValidatorThread(i);
+ }
+ Thread.sleep(DELAY*1000);
+ for (TestThread testThread : threads) {
+ testThread.requestStop();
+ }
+ for (ValidatorThread validator : validators) {
+ validator.requestStop();
+ }
+ for (TestThread testThread : threads) {
+ testThread.join();
+ }
+ for (ValidatorThread validator : validators) {
+ validator.join();
+ }
+ int addedTriples = 0;
+ for (TestThread testThread : threads) {
+ addedTriples += testThread.getAddedTripleCount();
+ }
+ int graphTriples = 0;
+ log.info("Test created {} graphs with {} triples", mGraphs.size(), addedTriples);
+ for(int i = 0;i < mGraphs.size(); i++){
+ MGraph graph = mGraphs.get(i);
+ graphTriples += graph.size();
+ log.info(" > Grpah {}: {} triples",i,graph.size());
+ for (Triple testTriple : testTriplesList.get(i)) {
+ Assert.assertTrue(graph.contains(testTriple));
+ }
+ }
+ Assert.assertEquals(addedTriples, graphTriples);
+ }
+ @AfterClass
+ public static void cleanUpDirectory() throws IOException {
+ provider.deactivate(null);
+ try {
+ TdbTcProvider.delete(tempFile);
+ } catch (IOException e) {
+ System.err.println("Failed removing tempfile "+tempFile);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTest.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTest.java b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTest.java
new file mode 100644
index 0000000..91791c3
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTest.java
@@ -0,0 +1,143 @@
+package org.apache.clerezza.rdf.jena.tdb.storage;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+*/
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+
+import org.apache.clerezza.rdf.core.BNode;
+import org.apache.clerezza.rdf.core.Literal;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.felix.scr.annotations.Activate;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.wymiwyg.commons.util.Util;
+
+
+public class MultiThreadedTest {
+
+
+
+ /**
+ * how many threads to start
+ */
+ private static final int THREAD_COUNT = 200;
+ /**
+ * how many seconds to let them run
+ */
+ private static final int DELAY = 15;
+
+
+ private MGraph mGraph;
+ private Set<Triple> testTriples = Collections.synchronizedSet(new HashSet<Triple>());
+
+ class TestThread extends Thread {
+
+ private final int id;
+ private boolean stopRequested;
+ private int addedTripleCount = 0;
+ private Object exception;
+
+ public TestThread(final int id) {
+ this.id = id;
+ start();
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+
+ @Override
+ public void run() {
+ while (!stopRequested) {
+ try {
+ Literal randomLiteral = new PlainLiteralImpl(Util.createRandomString(22));
+ Triple triple = new TripleImpl(new BNode(), new UriRef("http://example.com/property"), randomLiteral);
+ mGraph.add(triple);
+ addedTripleCount++;
+ if ((addedTripleCount % 100) == 0) {
+ testTriples.add(triple);
+ }
+ } catch (Exception e) {
+ exception = e;
+ }
+ }
+ }
+
+ public int getAddedTripleCount() {
+ return addedTripleCount;
+ }
+
+ }
+
+
+
+ @Before
+ public void setUp() throws IOException {
+ File tempFile;
+ UriRef MGRAPHNAME = new UriRef("http://text.example.org/");
+ TdbTcProvider tdbTcProvider;
+ tempFile = File.createTempFile("tdbtest", null);
+ tempFile.delete();
+ tempFile.mkdirs();
+ tdbTcProvider = new TdbTcProvider(tempFile);
+ tdbTcProvider.activate(null);
+ mGraph = tdbTcProvider.createMGraph(MGRAPHNAME);
+ }
+
+ @Test
+ public void perform() throws InterruptedException {
+ TestThread[] threads = new TestThread[THREAD_COUNT];
+ for (int i = 0; i < threads.length; i++) {
+ threads[i] = new TestThread(i);
+ }
+ Thread.sleep(DELAY*1000);
+ for (TestThread testThread : threads) {
+ testThread.requestStop();
+ }
+ for (TestThread testThread : threads) {
+ testThread.join();
+ }
+ int addedTriples = 0;
+ for (TestThread testThread : threads) {
+ addedTriples += testThread.getAddedTripleCount();
+ }
+ Assert.assertEquals(addedTriples, mGraph.size());
+ for (Triple testTriple : testTriples) {
+ Assert.assertTrue(mGraph.contains(testTriple));
+ }
+ for (TestThread testThread : threads) {
+ Assert.assertNull(testThread.exception);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTestSingleTdb.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTestSingleTdb.java b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTestSingleTdb.java
new file mode 100644
index 0000000..76505b3
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/MultiThreadedTestSingleTdb.java
@@ -0,0 +1,150 @@
+package org.apache.clerezza.rdf.jena.tdb.storage;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+*/
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+
+import org.apache.clerezza.rdf.core.BNode;
+import org.apache.clerezza.rdf.core.Literal;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.TcProvider;
+import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.felix.scr.annotations.Activate;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.service.cm.ConfigurationException;
+import org.wymiwyg.commons.util.Util;
+
+
+public class MultiThreadedTestSingleTdb {
+
+
+
+ /**
+ * how many threads to start
+ */
+ private static final int THREAD_COUNT = 100;
+ /**
+ * how many seconds to let them run
+ */
+ private static final int DELAY = 15;
+
+
+ private MGraph mGraph;
+ private Set<Triple> testTriples = Collections.synchronizedSet(new HashSet<Triple>());
+
+ class TestThread extends Thread {
+
+ private final int id;
+ private boolean stopRequested;
+ private int addedTripleCount = 0;
+ private Object exception;
+
+ public TestThread(final int id) {
+ this.id = id;
+ start();
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+
+ @Override
+ public void run() {
+ while (!stopRequested) {
+ try {
+ Literal randomLiteral = new PlainLiteralImpl(Util.createRandomString(22));
+ Triple triple = new TripleImpl(new BNode(), new UriRef("http://example.com/property"), randomLiteral);
+ mGraph.add(triple);
+ addedTripleCount++;
+ if ((addedTripleCount % 100) == 0) {
+ testTriples.add(triple);
+ }
+ } catch (Exception e) {
+ exception = e;
+ }
+ }
+ }
+
+ public int getAddedTripleCount() {
+ return addedTripleCount;
+ }
+
+ }
+
+
+
+ @Before
+ public void setUp() throws IOException, ConfigurationException {
+ File tempFile;
+ UriRef MGRAPHNAME = new UriRef("http://text.example.org/");
+ TcProvider tdbTcProvider;
+ tempFile = File.createTempFile("tdbtest", null);
+ tempFile.delete();
+ tempFile.mkdirs();
+ Dictionary<String, Object> dict = new Hashtable<String, Object>();
+ dict.put(SingleTdbDatasetTcProvider.TDB_DIR, tempFile.getAbsolutePath());
+ tdbTcProvider = new SingleTdbDatasetTcProvider(dict);
+ //tdbTcProvider.activate(null);
+ mGraph = tdbTcProvider.createMGraph(MGRAPHNAME);
+ }
+
+ @Test
+ public void perform() throws InterruptedException {
+ TestThread[] threads = new TestThread[THREAD_COUNT];
+ for (int i = 0; i < threads.length; i++) {
+ threads[i] = new TestThread(i);
+ }
+ Thread.sleep(DELAY*1000);
+ for (TestThread testThread : threads) {
+ testThread.requestStop();
+ }
+ for (TestThread testThread : threads) {
+ testThread.join();
+ }
+ int addedTriples = 0;
+ for (TestThread testThread : threads) {
+ addedTriples += testThread.getAddedTripleCount();
+ }
+ Assert.assertEquals(addedTriples, mGraph.size());
+ for (Triple testTriple : testTriples) {
+ Assert.assertTrue(mGraph.contains(testTriple));
+ }
+ for (TestThread testThread : threads) {
+ Assert.assertNull(testThread.exception);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetMGraphTest.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetMGraphTest.java b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetMGraphTest.java
new file mode 100644
index 0000000..cc3741b
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetMGraphTest.java
@@ -0,0 +1,56 @@
+package org.apache.clerezza.rdf.jena.tdb.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.test.MGraphTest;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.osgi.service.cm.ConfigurationException;
+
+public class SingleTdbDatasetMGraphTest extends MGraphTest {
+
+ private static final String MGRAPHNAME_PREFIX = "http://text.example.org/testGraph";
+ private static UriRef UNION_GRAPH_NAME = new UriRef("http://www.example.org/unionGraph");
+ private static int testGraphCounter = 0;
+
+ private static File tempFile;
+ private static Dictionary<String,Object> config;
+ private static SingleTdbDatasetTcProvider provider;
+
+ @BeforeClass
+ public static void setup() throws IOException, ConfigurationException {
+ tempFile = File.createTempFile("tdbdatasettest", null);
+ tempFile.delete();
+ tempFile.mkdirs();
+ config = new Hashtable<String,Object>();
+ config.put(SingleTdbDatasetTcProvider.TDB_DIR, tempFile.getAbsolutePath());
+ config.put(SingleTdbDatasetTcProvider.DEFAULT_GRAPH_NAME, UNION_GRAPH_NAME.getUnicodeString());
+ provider = new SingleTdbDatasetTcProvider(config);
+ }
+
+ @AfterClass
+ public static void cleanUpDirectory() throws IOException {
+ for(int i = 0; i < testGraphCounter;i++){
+ provider.deleteTripleCollection(new UriRef(MGRAPHNAME_PREFIX+i));
+ }
+ provider.deactivate(null);
+ try {
+ TdbTcProvider.delete(tempFile);
+ } catch (IOException e) {
+ System.err.println("Couldn't remove "+tempFile);
+ }
+ }
+
+ @Override
+ protected MGraph getEmptyMGraph() {
+ MGraph graph = provider.createMGraph(new UriRef(MGRAPHNAME_PREFIX+testGraphCounter));
+ testGraphCounter++;
+ return graph;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProviderTest.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProviderTest.java b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProviderTest.java
new file mode 100644
index 0000000..b3849dd
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/SingleTdbDatasetTcProviderTest.java
@@ -0,0 +1,168 @@
+package org.apache.clerezza.rdf.jena.tdb.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.NonLiteral;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.NoSuchEntityException;
+import org.apache.clerezza.rdf.core.access.TcProvider;
+import org.apache.clerezza.rdf.core.impl.PlainLiteralImpl;
+import org.apache.clerezza.rdf.core.impl.SimpleMGraph;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.core.test.TcProviderTest;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.service.cm.ConfigurationException;
+
+public class SingleTdbDatasetTcProviderTest extends TcProviderTest {
+
+ private static File tempFile;
+ private static Dictionary<String,Object> config;
+ private static SingleTdbDatasetTcProvider provider;
+ private static UriRef UNION_GRAPH_NAME = new UriRef("http://www.example.org/unionGraph");
+
+ @Before
+ public void setup() throws IOException, ConfigurationException {
+ tempFile = File.createTempFile("tdbdatasettest", null);
+ tempFile.delete();
+ tempFile.mkdirs();
+ config = new Hashtable<String,Object>();
+ config.put(SingleTdbDatasetTcProvider.TDB_DIR, tempFile.getAbsolutePath());
+ config.put(SingleTdbDatasetTcProvider.DEFAULT_GRAPH_NAME, UNION_GRAPH_NAME.getUnicodeString());
+ //config.put(SingleTdbDatasetTcProvider.USE_GRAPH_NAME_SUFFIXES, true);
+ }
+
+ @Override
+ protected TcProvider getInstance() {
+ //tests want us to deactivate/activate the TcProvider on multiple calls
+ //to getInstance within the same test
+ if(provider !=null){
+ try {
+ provider.deactivate(null);
+ provider = null;
+ } catch (Exception e) {
+ System.err.println("Error cleaning up: "+e.getMessage());
+ }
+ }
+ try {
+ provider = new SingleTdbDatasetTcProvider(config);
+ } catch (Exception e) {
+ throw new RuntimeException("forwarding ...",e);
+ }
+ return provider;
+ }
+
+ @After
+ public void cleanData() throws IOException{
+ //We need to remove all remaining data after a test
+ if(provider != null){
+ try {
+ provider.deactivate(null);
+ TdbTcProvider.delete(tempFile);
+ provider = null;
+ } catch (Exception e) {
+ System.err.println("Error cleaning up: "+e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * The union graph is read only!
+ */
+ @Test(expected=NoSuchEntityException.class)
+ public void testUnionMgraph(){
+ TcProvider provider = getInstance();
+ provider.getMGraph(UNION_GRAPH_NAME);
+ }
+
+ /**
+ * Assert union graph on an empty dataset
+ */
+ @Test
+ public void testEmptyUnionGraph(){
+ TcProvider provider = getInstance();
+ Graph graph = provider.getGraph(UNION_GRAPH_NAME);
+ Assert.assertNotNull(graph);
+ }
+
+ @Test
+ public void testUnionGraph() throws Exception{
+ TcProvider provider = getInstance();
+ UriRef type = new UriRef("http://www.w3.org/2000/01/rdf-schema#type");
+ UriRef name = new UriRef("http://schema.org/name");
+ UriRef personType = new UriRef("http://schema.org/Person");
+ UriRef companyType = new UriRef("http://schema.org/Company");
+ UriRef worksFor = new UriRef("http://schema.org/works-for");
+
+ //create a graph with persons
+ MGraph persons = new SimpleMGraph();
+ UriRef tim = new UriRef("http://people.org/tim.johnson");
+ persons.add(new TripleImpl(tim, type, personType));
+ persons.add(new TripleImpl(tim, name, new PlainLiteralImpl("Tim Johnson")));
+ UriRef john = new UriRef("http://people.org/john.swenson");
+ persons.add(new TripleImpl(john, type, personType));
+ persons.add(new TripleImpl(john, name, new PlainLiteralImpl("John Swenson")));
+ provider.createGraph(new UriRef("urn:persons"), persons.getGraph());
+
+ //create a MGraph with data about persons
+ MGraph orgdata = provider.createMGraph(new UriRef("urn:orgdata"));
+ UriRef talinor = new UriRef("http://company.org/talinor");
+ orgdata.add(new TripleImpl(talinor, type, companyType));
+ orgdata.add(new TripleImpl(talinor, name, new PlainLiteralImpl("Talinor Inc.")));
+ orgdata.add(new TripleImpl(john, worksFor, talinor));
+ UriRef kondalor = new UriRef("http://company.org/kondalor");
+ orgdata.add(new TripleImpl(kondalor, type, companyType));
+ orgdata.add(new TripleImpl(kondalor, name, new PlainLiteralImpl("Kondalor Ges.m.b.H.")));
+ orgdata.add(new TripleImpl(tim, worksFor, kondalor));
+
+ //now get the union graph
+ Graph data = provider.getGraph(UNION_GRAPH_NAME);
+ Assert.assertNotNull(data);
+ //CLEREZZA-714: getTriples need to correctly return the UnionGraph
+ data = (Graph)provider.getTriples(UNION_GRAPH_NAME);
+ Assert.assertNotNull(data);
+ //NOTE: Jena TDB does not support getSize for the union graph
+// int expectedTripleCount = persons.size()+orgdata.size();
+// Assert.assertEquals("Uniongraph has "+data.size()
+// +" triples (expected "+expectedTripleCount+")",
+// expectedTripleCount, data.size());
+ Iterator<Triple> it = data.filter(null, type, companyType);
+ Set<UriRef> expected = new HashSet<UriRef>(Arrays.asList(talinor,kondalor));
+ while(it.hasNext()){
+ NonLiteral subject = it.next().getSubject();
+ Assert.assertTrue("Unexpected "+subject, expected.remove(subject));
+ }
+ Assert.assertTrue("Missing "+expected, expected.isEmpty());
+
+ it = data.filter(null, type, personType);
+ expected = new HashSet<UriRef>(Arrays.asList(john,tim));
+ while(it.hasNext()){
+ NonLiteral subject = it.next().getSubject();
+ Assert.assertTrue("Unexpected "+subject, expected.remove(subject));
+ }
+ Assert.assertTrue("Missing "+expected, expected.isEmpty());
+ }
+
+ @Test
+ public void testListGraph(){
+ TcProvider provider = getInstance();
+ //No union graph in listMGraphs
+ Set<UriRef> mgl = provider.listMGraphs();
+ Assert.assertFalse("Mgraph list don't contain the read-only union-graph", mgl.contains(UNION_GRAPH_NAME));
+ //Union graph in listGraphs
+ Set<UriRef> gl = provider.listGraphs();
+ Assert.assertTrue("Graph list contain the read-only union-graph", gl.contains(UNION_GRAPH_NAME));
+ }
+}
http://git-wip-us.apache.org/repos/asf/clerezza/blob/dac431ca/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbMGraphTest.java
----------------------------------------------------------------------
diff --git a/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbMGraphTest.java b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbMGraphTest.java
new file mode 100644
index 0000000..e09c0e4
--- /dev/null
+++ b/rdf/jena/tdb.storage/src/test/java/org/apache/clerezza/rdf/jena/tdb/storage/TdbMGraphTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.clerezza.rdf.jena.tdb.storage;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Iterator;
+import org.apache.clerezza.rdf.core.BNode;
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TypedLiteral;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.core.test.MGraphTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ * @author reto
+ */
+public class TdbMGraphTest extends MGraphTest {
+ private static File tempFile;
+ final private UriRef MGRAPHNAME = new UriRef("http://text.example.org/");
+ static private TdbTcProvider tdbTcProvider;
+
+ @BeforeClass
+ public static void setupDirectory() throws IOException {
+ tempFile = File.createTempFile("tdbtest", null);
+ tempFile.delete();
+ tempFile.mkdirs();
+ tdbTcProvider = new TdbTcProvider(tempFile);
+ }
+
+ @AfterClass
+ public static void cleanUpDirectory() throws IOException {
+ try {
+ TdbTcProvider.delete(tempFile);
+ } catch (IOException e) {
+ System.err.println("failed to delete temp directory: "+tempFile);
+ }
+ }
+
+ @After
+ public void cleanUpGraph() {
+ tdbTcProvider.deleteTripleCollection(MGRAPHNAME);
+ }
+
+ @Override
+ protected MGraph getEmptyMGraph() {
+ return tdbTcProvider.createMGraph(MGRAPHNAME);
+ }
+
+ @Test
+ public void dateStorage() {
+ MGraph graph = getEmptyMGraph();
+ Date date = new Date(0);
+ LiteralFactory literalFactory = LiteralFactory.getInstance();
+ TypedLiteral dateLiteral = literalFactory.createTypedLiteral(date);
+ Triple triple = new TripleImpl(new BNode(), new UriRef("http://example.com/property"), dateLiteral);
+ graph.add(triple);
+ Assert.assertTrue(graph.contains(triple));
+ }
+
+ @Test
+ public void dateStorage2() {
+ MGraph graph = getEmptyMGraph();
+ Date date = new Date(0);
+ LiteralFactory literalFactory = LiteralFactory.getInstance();
+ TypedLiteral dateLiteral = literalFactory.createTypedLiteral(date);
+ System.out.println(dateLiteral);
+ UriRef property = new UriRef("http://example.com/property");
+ Triple triple = new TripleImpl(new BNode(), property, dateLiteral);
+ graph.add(triple);
+
+ Triple tripleFromGraph = null;
+ Iterator<Triple> propertyTriples = graph.filter(null, property, dateLiteral);
+ if (propertyTriples.hasNext()) {
+ tripleFromGraph = propertyTriples.next();
+ } else {
+ Assert.assertTrue(false);
+ }
+ Assert.assertEquals(dateLiteral, tripleFromGraph.getObject());
+ }
+
+}