Package org.apache.clerezza.rdf.jena.tdb.storage

Source Code of org.apache.clerezza.rdf.jena.tdb.storage.TdbTcProvider$SyncThread

/*
* 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 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.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.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
*
* @scr.component immediate="true"
* @scr.service interface="org.apache.clerezza.rdf.core.access.WeightedTcProvider"
* @scr.property name="weight" type="Integer" value="105"
*
*/
@Component(metatype=true, immediate=true)
@Service(WeightedTcProvider.class)
@Property(name="weight", intValue=105)
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 final Map<File, Dataset> dir2Dataset = new HashMap<File, Dataset>();
    private static final Logger log = LoggerFactory.getLogger(TdbTcProvider.class);
    private int weight = 105;
   
    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));
        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();
       
        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) {
                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
        //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);
        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);
                    mGraphMap.put(uri, new LockableMGraphWrapper(getMGraph(new File(mGraphsDir, mGraphDirName))));
                } 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 (Dataset dataset : dir2Dataset.values()) {
                TDB.sync(dataset);
            }
        }
    }
}
TOP

Related Classes of org.apache.clerezza.rdf.jena.tdb.storage.TdbTcProvider$SyncThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.