package com.redhat.lightblue.migrator.facade.sharedstore; import java.net.URL; import java.util.LinkedList; import java.util.NoSuchElementException; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * SharedStore implementation using ehcache. Creates a cache object per service * and uses thread id as key to avoid conflicts. There is an assumption that * both legacy and lightblue services create entities in the same order * (push/pop). * * @author mpatercz * */ public class SharedStoreImpl implements SharedStore { private static final Logger log = LoggerFactory.getLogger(SharedStoreImpl.class); // singleton private CacheManager cacheManager; private Cache cache; public SharedStoreImpl(String implementationName) { this(implementationName, null); } public SharedStoreImpl(String implementationName, URL ehcacheConfigFile) { log.debug("Initializing id cache for " + implementationName); if (ehcacheConfigFile == null) { cacheManager = CacheManager.create(SharedStoreImpl.class.getResourceAsStream("/ehcache.xml")); } else { cacheManager = CacheManager.create(ehcacheConfigFile); } cacheManager.addCacheIfAbsent(implementationName); cache = cacheManager.getCache(implementationName); } @Override public void push(Object obj) { long threadId = Thread.currentThread().getId(); if (log.isDebugEnabled()) { log.debug("Storing obj=" + obj + " for " + cache.getName() + ", thread=" + threadId); } Element el = cache.get(threadId); LinkedList<Object> list; if (el == null) { list = new LinkedList<Object>(); } else { list = (LinkedList<Object>) el.getObjectValue(); } list.add(obj); cache.put(new Element(threadId, list)); } @Override public Object pop() { long threadId = Thread.currentThread().getId(); log.debug("Restoring id for " + cache.getName() + " thread=" + threadId); Element el = cache.get(threadId); if (el == null) { throw new SharedStoreException(cache.getName(), threadId); } @SuppressWarnings("unchecked") LinkedList<Long> list = (LinkedList<Long>) el.getObjectValue(); try { return list.removeFirst(); } catch (NoSuchElementException e) { throw new SharedStoreException(cache.getName(), threadId); } } @Override public void copyFromThread(long sourceThreadId) { long threadId = Thread.currentThread().getId(); log.debug("copyFromThread thread=" + sourceThreadId + " to thread=" + threadId); Element sourceEl = cache.get(sourceThreadId); if (sourceEl != null) { @SuppressWarnings("unchecked") LinkedList<Object> list = (LinkedList<Object>) sourceEl.getObjectValue(); // copy by reference cache.put(new Element(threadId, list)); log.debug("Copied key value pairs from thread=" + sourceThreadId + " to thread=" + threadId); } Element sourceEl2 = cache.get("isDualMigrationPhase-" + sourceThreadId); if (sourceEl2 != null) { Boolean isDualMigrationPhase = (Boolean) sourceEl2.getObjectValue(); // copy by reference cache.put(new Element("isDualMigrationPhase-" + threadId, isDualMigrationPhase)); log.debug("Copied isDualMigrationPhase from thread=" + sourceThreadId + " to thread=" + threadId); } } @Override public boolean isDualMigrationPhase() { long threadId = Thread.currentThread().getId(); log.debug("Reading isDualMigrationPhase for " + cache.getName() + " thread=" + threadId); Element el = cache.get("isDualMigrationPhase-" + threadId); if (el == null) { throw new SharedStoreException(cache.getName(), threadId); } return (Boolean) el.getObjectValue(); } public void setDualMigrationPhase(boolean isDualMigrationPhase) { long threadId = Thread.currentThread().getId(); log.debug("Storing isDualMigrationPhase for " + cache.getName() + " thread=" + threadId); cache.put(new Element("isDualMigrationPhase-" + threadId, isDualMigrationPhase)); } @Override public void clear() { long threadId = Thread.currentThread().getId(); log.debug("Clearing data for " + cache.getName() + " thread=" + threadId); cache.remove(threadId); cache.remove("isDualMigrationPhase-" + threadId); } }