Java tutorial
/** * 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); } }