Package at.newmedialab.ldclient.service

Source Code of at.newmedialab.ldclient.service.LDCache

/**
* Copyright (C) 2013 Salzburg Research.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.newmedialab.ldclient.service;

import at.newmedialab.ldclient.api.LDCacheProvider;
import at.newmedialab.ldclient.exception.LDClientException;
import at.newmedialab.ldclient.model.CacheEntry;
import at.newmedialab.ldclient.model.ClientResponse;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
* Add file description here!
* <p/>
* Author: Sebastian Schaffert
*/
public class LDCache {

    private static final String CTX_CACHE = "http://www.newmedialab.at/ldclient/cache";

    private Logger log = LoggerFactory.getLogger(LDCache.class);

    private LDClient clientService;

    private LDEndpoints endpointService;


    private ThreadLocal<Boolean> inProgress = new ThreadLocal<Boolean>();


    private LDCacheProvider cacheProvider;

    // lock a resource while refreshing it so that not several threads trigger a refresh at the same time
    private HashMap<URI,Lock> resourceLocks;

    private Configuration config;


    public LDCache(LDCacheProvider ldCacheProvider) {
        log.info("Linked Data Caching Service initialising ...");
        try {
            config = new PropertiesConfiguration("ldclient.properties");
        } catch (ConfigurationException e) {
            log.warn("could not load configuration file ldclient.properties from current directory, home directory, or classpath");
        }

        resourceLocks = new HashMap<URI, Lock>();

        cacheProvider   = ldCacheProvider;
        clientService   = new LDClient();
        endpointService = new LDEndpoints();
    }


    private void lockResource(URI resource) {
        Lock lock;
        synchronized (resourceLocks) {
            lock = resourceLocks.get(resource);
            if(lock == null) {
                lock = new ReentrantLock();
                resourceLocks.put(resource,lock);
            }
        }
        lock.lock();
    }

    private void unlockResource(URI resource) {
        Lock lock;
        synchronized (resourceLocks) {
            lock = resourceLocks.remove(resource);
        }
        if(lock != null) {
            lock.unlock();
        }
    }


    /**
     * Refresh the cached resource passed as argument. The method will do nothing for local resources.
     * Calling the method will carry out the following tasks:
     * 1. check whether the resource is a remote resource; if no, returns immediately
     * 2. check whether the resource has a cache entry; if no, goto 4
     * 3. check whether the expiry time of the cache entry has passed; if no, returns immediately
     * 4. retrieve the triples for the resource from the Linked Data Cloud using the methods offered by the
     * LinkedDataClientService (registered endpoints etc); returns immediately if the result is null or
     * an exception is thrown
     * 5. remove all old triples for the resource and add all new triples for the resource
     * 6. create new expiry information of the cache entry and persist it in the transaction
     *
     * @param resource
     */
    public void refreshResource(URI resource) {

        lockResource(resource);
        try {

            // 2. check whether the resource has a cache entry; if no, goto 4
            CacheEntry entry = getCacheEntry(resource);

            // 3. check whether the expiry time of the cache entry has passed; if no, returns immediately
            if(entry != null && entry.getExpiryDate().after(new Date())) {
                log.info("not refreshing resource {}, as the cached entry is not yet expired",resource);
                return;
            }

            // 4.
            log.debug("refreshing resource {}",resource);
            try {
                ClientResponse response = clientService.retrieveResource(resource);

                if(response != null) {
                    log.info("refreshed resource {}",resource);

                    URI context = cacheProvider.getTripleRepository().getValueFactory().createURI(CTX_CACHE);


                    RepositoryConnection lmfConnection = cacheProvider.getTripleRepository().getConnection();
                    RepositoryConnection respConnection = response.getTriples().getConnection();

                    lmfConnection.remove(resource,null,null,context);


                    RepositoryResult<Statement> triples = respConnection.getStatements(null,null,null,true);
                    while(triples.hasNext()) {
                        Statement triple = triples.next();
                        try {
                            lmfConnection.add(triple,context);
                        } catch (RuntimeException ex) {
                            log.warn("not adding triple {}: an exception occurred ({})",triple,ex.getMessage());
                        }
                    }
                    lmfConnection.commit();

                    lmfConnection.close();
                    respConnection.close();

                    CacheEntry newEntry = new CacheEntry();
                    newEntry.setResource(resource);
                    newEntry.setExpiryDate(response.getExpires());
                    newEntry.setLastRetrieved(new Date());
                    if(entry != null) {
                        newEntry.setUpdateCount(entry.getUpdateCount()+1);
                    } else {
                        newEntry.setUpdateCount((long)1);
                    }

                    cacheProvider.getMetadataRepository().put(resource.stringValue(),newEntry);

                }

            } catch (LDClientException e) {
                // on exception, save an expiry information and retry in one day
                CacheEntry newEntry = new CacheEntry();
                newEntry.setResource(resource);
                newEntry.setExpiryDate(new Date(System.currentTimeMillis() + config.getInt("expiry", 86400)*1000));
                newEntry.setLastRetrieved(new Date());
                if(entry != null) {
                    newEntry.setUpdateCount(entry.getUpdateCount()+1);
                } else {
                    newEntry.setUpdateCount((long)1);
                }

                cacheProvider.getMetadataRepository().put(resource.stringValue(), newEntry);

                log.error("refreshing the remote resource {} from the Linked Data Cloud failed ({})",resource,e.getMessage());
                return;
            } catch (RepositoryException e) {
                log.error("repository error while refreshing the remote resource {} from the Linked Data Cloud", resource, e);
                return;
            }
        } finally {
            unlockResource(resource);
        }

    }


    private CacheEntry getCacheEntry(URI resource) {
        return cacheProvider.getMetadataRepository().get(resource.stringValue());
    }

    public LDEndpoints getEndpointService() {
        return endpointService;
    }

}
TOP

Related Classes of at.newmedialab.ldclient.service.LDCache

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.