/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos 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 Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.utils.cache.ehcache; import java.util.Collections; import java.util.List; import net.sf.ehcache.CacheException; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Ehcache; import net.sf.ehcache.Status; import net.sf.ehcache.distribution.CacheManagerPeerProvider; import net.sf.ehcache.distribution.CachePeer; import nl.strohalm.cyclos.utils.CurrentApplicationContext; import nl.strohalm.cyclos.utils.HazelcastHelper; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.ITopic; import com.hazelcast.core.Message; import com.hazelcast.core.MessageListener; /** * Listens to a Hazelcast topic for remote cache operations and apply it in the local cache * * @author luis */ public class HazelcastCacheManagerPeerProvider implements CacheManagerPeerProvider, MessageListener<CacheEvictionEvent> { public static final String SCHEME_NAME = "Hazelcast"; private static final Log LOG = LogFactory.getLog(HazelcastCacheManagerPeerProvider.class); /** * Given an {@link CacheManager} get the corresponding instance of this class. */ public static HazelcastCacheManagerPeerProvider getCachePeerProvider(final CacheManager cacheManager) { final CacheManagerPeerProvider provider = cacheManager.getCacheManagerPeerProvider(SCHEME_NAME); if (provider == null) { LOG.warn("No CacheManagerPeerProvider registered for " + SCHEME_NAME + " scheme."); return null; } if (!(provider instanceof HazelcastCacheManagerPeerProvider)) { LOG.warn("CacheManagerPeerProvider for scheme " + SCHEME_NAME + " cannot be cast to " + HazelcastCacheManagerPeerProvider.class.getName()); return null; } return (HazelcastCacheManagerPeerProvider) provider; } /** * Given an {@link Ehcache} get the corresponding instance of this class. */ public static HazelcastCacheManagerPeerProvider getCachePeerProvider(final Ehcache cache) { final CacheManager cacheManager = cache.getCacheManager(); return getCachePeerProvider(cacheManager); } /** * Returns the topic for the given cache */ public static ITopic<CacheEvictionEvent> getTopic(final Ehcache cache) { return getCachePeerProvider(cache).getTopic(); } private final CacheManager cacheManager; private ITopic<CacheEvictionEvent> topic; private Status status = Status.STATUS_UNINITIALISED; public HazelcastCacheManagerPeerProvider(final CacheManager cacheManager) { this.cacheManager = cacheManager; } @Override public void dispose() throws CacheException { // Topic is already disposed on hazelcast shutdown status = Status.STATUS_SHUTDOWN; } @Override public String getScheme() { return SCHEME_NAME; } /** * @return the {@link Status} of the manager */ public Status getStatus() { return status; } @Override public long getTimeForClusterToForm() { return 0; } public ITopic<CacheEvictionEvent> getTopic() { return topic; } @Override public void init() { ApplicationContext applicationContext = CurrentApplicationContext.CURRENT.get(); HazelcastInstance hazelcastInstance = HazelcastHelper.getHazelcastInstance(applicationContext); topic = hazelcastInstance.getTopic("cyclos.EhCacheEvictionReplication"); topic.addMessageListener(this); status = Status.STATUS_ALIVE; LOG.info("EhCache replication has started using Hazelcast"); } @Override public List<CachePeer> listRemoteCachePeers(final Ehcache cache) throws CacheException { // Ignore, only used for RMI return Collections.emptyList(); } @Override public void onMessage(final Message<CacheEvictionEvent> message) { CacheEvictionEvent event = message.getMessageObject(); if (LOG.isDebugEnabled()) { LOG.debug("Received cache eviction event: " + event); } Ehcache cache = cacheManager.getEhcache(event.getName()); // No need to evict something in a cache which was not yet created if (cache != null) { Object key = event.getKey(); if (key == null) { cache.removeAll(true); } else { cache.remove(key, true); } } } @Override public void registerPeer(final String rmiUrl) { // Ignore, only used for RMI } @Override public void unregisterPeer(final String rmiUrl) { // Ignore, only used for RMI } }