Package net.fortytwo.linkeddata

Source Code of net.fortytwo.linkeddata.CachingMetadata

package net.fortytwo.linkeddata;

import info.aduna.iteration.CloseableIteration;
import net.fortytwo.ripple.RippleException;
import org.openrdf.model.Literal;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
import org.openrdf.sail.SailConnection;
import org.openrdf.sail.SailException;

import java.util.LinkedHashMap;
import java.util.Map;

/**
* A collection of caching metadata for aggregated Linked Data.
* A complete set of metadata is maintained in the underlying triple store,
* while a subset of the data is kept in a fast in-memory cache.
*
* @author Joshua Shinavier (http://fortytwo.net)
*/
public class CachingMetadata {
    private final InMemoryCache memos;

    private final ValueFactory valueFactory;

    // A special context memo to indicate an already-known persistence miss.
    private final CacheEntry miss;

    public CachingMetadata(final int capacity,
                           final ValueFactory valueFactory) throws RippleException {
        memos = new InMemoryCache(capacity);

        this.valueFactory = valueFactory;

        miss = new CacheEntry();
    }

    public CacheEntry getMemo(final String graphUri,
                              final SailConnection sc) throws RippleException {
        CacheEntry memo = memos.get(graphUri);

        // If the memo is not cached
        if (null == memo) {
            // Attempt to retrieve the memo from the persistent store.
            try {
                memo = retrieveMemo(graphUri, sc);
            } catch (SailException e) {
                throw new RippleException(e);
            }

            if (null == memo) {
                // There is no such memo.  Cache the "miss" value to avoid future retrieval attempts.
                memos.put(graphUri, miss);
            } else {
                // The memo exists.  Cache it.
                memos.put(graphUri, memo);
            }
        }

        return memo;
    }

    // Writes caching metadata to the base Sail.
    // Note: for now, this metadata resides in the null context.
    public void setMemo(final String graphUri,
                        final CacheEntry memo,
                        final SailConnection sc) throws RippleException {
        try {
            URI s = valueFactory.createURI(graphUri);

            Literal memoLit = valueFactory.createLiteral(memo.toString());
            sc.removeStatements(s, LinkedDataCache.CACHE_MEMO, null, LinkedDataCache.CACHE_GRAPH);
            sc.addStatement(s, LinkedDataCache.CACHE_MEMO, memoLit, LinkedDataCache.CACHE_GRAPH);

            memos.put(graphUri, memo);
        } catch (SailException e) {
            throw new RippleException(e);
        }
    }

    // Restores dereferencer state by reading success and failure memos from
    // the last session (if present).
    private CacheEntry retrieveMemo(final String graphUri,
                                    final SailConnection sc) throws SailException, RippleException {
        CloseableIteration<? extends Statement, SailException> iter;

        iter = sc.getStatements(
                valueFactory.createURI(graphUri),
                LinkedDataCache.CACHE_MEMO,
                null,
                false,
                LinkedDataCache.CACHE_GRAPH);

        try {
            if (!iter.hasNext()) {
                return null;
            } else {
                // Note: if there are multiple statements (which there shouldn't be), make an arbitrary choice.
                Literal obj = (Literal) iter.next().getObject();

                return new CacheEntry(obj.getLabel());
            }
        } finally {
            iter.close();
        }
    }

    // A fast in-memory cache with an LRU replacement policy
    private class InMemoryCache extends LinkedHashMap<String, CacheEntry> {
        private final int maxCapacity;

        // Creates an access-order linked hashmap with the given maximum capacity.
        // Default values are used for initial capacity and load factor.
        public InMemoryCache(final int maxCapacity) {
            super(16, 0.75f, true);

            this.maxCapacity = maxCapacity;
        }

        @Override
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > maxCapacity;
        }
    }
}
TOP

Related Classes of net.fortytwo.linkeddata.CachingMetadata

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.