com.seajas.search.contender.replication.ModifierCache.java Source code

Java tutorial

Introduction

Here is the source code for com.seajas.search.contender.replication.ModifierCache.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.replication;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.seajas.search.bridge.profiler.ConversionUtils;
import com.seajas.search.bridge.profiler.model.modifier.Modifier;
import com.seajas.search.profiler.wsdl.modifier.IModifierListing;
import com.seajas.search.profiler.wsdl.modifier.UrlType;

/**
 * Read-most modifier cache implementation.
 * 
 * @author Jasper van Veghel <jasper@seajas.com>
 */
@Component
public class ModifierCache {
    /**
     * The logger.
     */
    private static final Logger logger = LoggerFactory.getLogger(ModifierCache.class);

    /**
     * Feed modifiers by their IDs.
     */
    private volatile Map<Integer, Modifier> feedModifiersById;

    /**
     * Result modifiers by their IDs.
     */
    private volatile Map<Integer, Modifier> resultModifiersById;

    /**
     * Reentrant read-write lock for feeds.
     */
    private volatile ReentrantReadWriteLock feedLock = new ReentrantReadWriteLock();

    /**
     * Reentrant read-write lock for results.
     */
    private volatile ReentrantReadWriteLock resultLock = new ReentrantReadWriteLock();

    /**
     * Bootstrap the cache.
     * 
     * @param modifierListingService
     */
    @Autowired
    public void setModifierListingService(final IModifierListing modifierListingService) {
        if (!ConversionUtils.validateModifierModelIntegrity())
            throw new IllegalStateException(
                    "Object copying does not account for all fields - model definition too new");

        feedModifiersById = new HashMap<Integer, Modifier>();
        resultModifiersById = new HashMap<Integer, Modifier>();

        for (com.seajas.search.bridge.profiler.wsdl.modifier.Modifier modifier : modifierListingService
                .retrieveAllFeedModifiers()) {
            logger.info("Adding feed modifier " + modifier.getId() + " with expression '"
                    + modifier.getUrlExpression() + "'");

            feedModifiersById.put(modifier.getId(), ConversionUtils.convertModifierWsToInternal(modifier));
        }

        for (com.seajas.search.bridge.profiler.wsdl.modifier.Modifier modifier : modifierListingService
                .retrieveAllResultModifiers()) {
            logger.info("Adding result modifier " + modifier.getId() + " with expression '"
                    + modifier.getUrlExpression() + "'");

            resultModifiersById.put(modifier.getId(), ConversionUtils.convertModifierWsToInternal(modifier));
        }
    }

    /**
     * Process an incoming update.
     * 
     * @param modifier
     */
    public void update(final Modifier modifier) {
        logger.info("Updating " + modifier.getUrlType() + " modifier with ID " + modifier.getId()
                + (modifier.getScripts() != null && modifier.getScripts().size() > 0
                        ? " and first script (id = " + modifier.getScripts().get(0).getId() + ") modification date "
                                + modifier.getScripts().get(0).getModificationDate()
                        : ""));

        if (modifier.getUrlType().name().equalsIgnoreCase(UrlType.FEED.name())) {
            feedLock.writeLock().lock();

            try {
                feedModifiersById.put(modifier.getId(), modifier);
            } finally {
                feedLock.writeLock().unlock();
            }
        } else {
            resultLock.writeLock().lock();

            try {
                resultModifiersById.put(modifier.getId(), modifier);
            } finally {
                resultLock.writeLock().unlock();
            }
        }
    }

    /**
     * Process an incoming delete.
     * 
     * @param id
     */
    public void delete(final Integer id) {
        feedLock.writeLock().lock();

        logger.info("Deleting modifier with ID " + id);

        try {
            feedModifiersById.remove(id);
        } finally {
            feedLock.writeLock().unlock();
        }

        resultLock.writeLock().lock();

        try {
            resultModifiersById.remove(id);
        } finally {
            resultLock.writeLock().unlock();
        }
    }

    /**
     * Retrieve a given feed modifier by its ID.
     * 
     * @param id
     * @return Modifier
     */
    public Modifier getFeedModifierById(final Integer id) {
        feedLock.readLock().lock();

        try {
            return feedModifiersById.get(id);
        } finally {
            feedLock.readLock().unlock();
        }
    }

    /**
     * Retrieve a given result modifier by its ID.
     * 
     * @param id
     * @return Modifier
     */
    public Modifier getResultModifierById(final Integer id) {
        resultLock.readLock().lock();

        try {
            return resultModifiersById.get(id);
        } finally {
            resultLock.readLock().unlock();
        }
    }

    /**
     * Retrieve a list of feed modifiers that match the given URL.
     * 
     * @param url
     * @return List<Modifier>
     */
    public List<Modifier> getFeedModifiersByUrlMatch(final String url) {
        feedLock.readLock().lock();

        try {
            List<Modifier> result = new ArrayList<Modifier>();

            for (Entry<Integer, Modifier> entry : feedModifiersById.entrySet())
                if (modifierMatchesUrl(entry.getValue(), url))
                    result.add(entry.getValue());

            return result;
        } finally {
            feedLock.readLock().unlock();
        }
    }

    /**
     * Retrieve a list of result modifiers that match the given URL.
     * 
     * @param url
     * @return List<Modifier>
     */
    public List<Modifier> getResultModifiersByUrlMatch(final String url) {
        resultLock.readLock().lock();

        try {
            List<Modifier> result = new ArrayList<Modifier>();

            for (Entry<Integer, Modifier> entry : resultModifiersById.entrySet())
                if (modifierMatchesUrl(entry.getValue(), url))
                    result.add(entry.getValue());

            return result;
        } finally {
            resultLock.readLock().unlock();
        }
    }

    /**
     * Determine whether the given modifier matches the URL.
     * 
     * @param modifier
     * @param url
     * @return boolean
     */
    private static boolean modifierMatchesUrl(final Modifier modifier, final String url) {
        if (logger.isDebugEnabled())
            logger.debug("Attempting to match modifier expression '" + modifier.getUrlExpression()
                    + "' against URL '" + url + "'");

        return Pattern.matches(modifier.getUrlExpression(), url);
    }
}