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());
+    }
+
+}