com.seajas.search.contender.service.cache.CacheService.java Source code

Java tutorial

Introduction

Here is the source code for com.seajas.search.contender.service.cache.CacheService.java

Source

/**
 * Copyright (C) 2013 Seajas, the Netherlands.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.seajas.search.contender.service.cache;

import com.seajas.search.bridge.jms.model.state.SourceElementState;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * The cache service.
 * 
 * @author Jasper van Veghel <jasper@seajas.com>
 */
@Service
public class CacheService {
    /**
     * The logger.
     */
    private static final Logger logger = LoggerFactory.getLogger(CacheService.class);

    /**
     * The archive cache.
     */
    @Autowired
    private Ehcache archiveCache;

    /**
     * The delete cache.
     */
    @Autowired
    private Ehcache deleteCache;

    /**
     * The element cache.
     */
    @Autowired
    private Ehcache elementCache;

    /**
     * The processing cache.
     */
    @Autowired
    private Ehcache processingCache;

    /**
     * The composite cache key.
     */
    private List<String> compositeKey;

    /**
     * Default constructor.
     */
    public CacheService() {
        // Do nothing
    }

    /**
     * Default constructor.
     * 
     * @param compositeKey
     */
    @Autowired
    public CacheService(@Value("${contender.project.cache.unique.key.composition}") final String compositeKey) {
        this.compositeKey = Arrays.asList(StringUtils.tokenizeToStringArray(compositeKey, ",", true, true));
    }

    /**
     * Add the given element URL to the element cache.
     * 
     * @param url
     */
    public void addElement(final String url) {
        if (elementCache.isKeyInCache(url)) {
            if (logger.isDebugEnabled())
                logger.debug("Element '" + url + "' already exists in the cache");

            return;
        } else if (logger.isDebugEnabled())
            logger.debug("Adding element entry '" + url + "'");

        elementCache.put(new Element(url, SourceElementState.Processed));
    }

    /**
     * Add the given archive URL to the archive cache.
     * 
     * @param url
     */
    public void addArchived(final String url) {
        if (archiveCache.isKeyInCache(url)) {
            if (logger.isDebugEnabled())
                logger.debug("Archive element '" + url + "' already exists in the cache");

            return;
        } else if (logger.isDebugEnabled())
            logger.debug("Adding archive element entry '" + url + "'");

        archiveCache.put(new Element(url, url));
    }

    /**
     * Add the given delete URL to the delete cache.
     * 
     * @param entry
     */
    public void addDeleted(final DeletedEntry entry) {
        if (deleteCache.isKeyInCache(entry.toString())) {
            if (logger.isDebugEnabled())
                logger.debug("Delete element '" + entry + "' already exists in the cache");

            return;
        } else if (logger.isDebugEnabled())
            logger.debug("Adding delete element entry '" + entry + "'");

        deleteCache.put(new Element(entry.toString(), entry));
    }

    /**
     * Invalidate the given element URL in the element cache.
     * 
     * @param url
     */
    public void invalidateElement(final String url) {
        if (elementCache.isKeyInCache(url)) {
            if (logger.isDebugEnabled())
                logger.debug("Element '" + url + "' already exists in the cache - overwriting as invalidated");
        } else if (logger.isDebugEnabled())
            logger.debug("Invalidating element entry '" + url + "'");

        elementCache.put(new Element(url, SourceElementState.Invalid));
    }

    /**
     * Determine whether the given URL has been processed or queued.
     * 
     * @param url
     * @return boolean
     */
    public boolean isCached(final String url) {
        // The element may live in the processingCache if it was previously reproduced but has not yet been added to the elementCache

        return elementCache.isKeyInCache(url) || processingCache.isKeyInCache(url);
    }

    /**
     * Determine whether the given URL has been previously archived.
     * 
     * @param url
     * @return boolean
     */
    public boolean isArchived(final String url) {
        return archiveCache.isKeyInCache(url);
    }

    /**
     * Delete the given element key.
     * 
     * @param url
     * @return boolean
     */
    public boolean deleteElement(final String url) {
        return elementCache.remove(url);
    }

    /**
     * Delete the given archive key.
     * 
     * @param url
     * @return boolean
     */
    public boolean deleteArchived(final String url) {
        return archiveCache.remove(url);
    }

    /**
     * Create a cache key from the URL and (optionally) the result parameters.
     * 
     * @param url
     * @param resultParameters
     * @return
     */
    public String createCompositeKey(final String url, final Map<String, String> resultParameters) {
        String idValue = url;

        if (compositeKey != null && compositeKey.size() > 0) {
            idValue = "";

            for (String field : compositeKey) {
                String fieldValue = null;

                if (field.equalsIgnoreCase("url"))
                    fieldValue = url;
                else if (resultParameters != null && resultParameters.containsKey(field)
                        && StringUtils.hasText(resultParameters.get(field))) {
                    fieldValue = resultParameters.get(field);
                } else if (logger.isDebugEnabled())
                    logger.debug(String.format(
                            "Not adding missing content metadata field '%s' (not necessarily an error)", field));

                if (fieldValue != null)
                    idValue += (idValue.length() > 0 ? " - " : "") + fieldValue;
            }
        }

        return idValue;
    }

    /**
     * A cache entry for deleted collection+link combinations.
     * 
     * @author Jasper van Veghel <jasper@seajas.com>
     */
    public static class DeletedEntry implements Serializable {
        /**
         * Serial version UID.
         */
        private static final long serialVersionUID = 1L;

        /**
         * The collection.
         */
        private final String collection;

        /**
         * The URL.
         */
        private final String url;

        /**
         * Default constructor.
         * 
         * @param collection
         * @param url
         */
        public DeletedEntry(final String collection, final String url) {
            this.collection = collection;
            this.url = url;
        }

        /**
         * Retrieve the collection.
         * 
         * @return String
         */
        public String getCollection() {
            return collection;
        }

        /**
         * Retrieve the url.
         * 
         * @return String
         */
        public String getUrl() {
            return url;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return collection + "/" + url;
        }
    }
}