package pt.ist.fenixframework.backend.infinispan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import org.infinispan.Cache; import org.infinispan.manager.CacheContainer; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.manager.DefaultCacheManager; import pt.ist.fenixframework.DomainObject; import pt.ist.fenixframework.DomainRoot; import pt.ist.fenixframework.FenixFramework; import pt.ist.fenixframework.TransactionManager; import pt.ist.fenixframework.backend.BackEnd; import pt.ist.fenixframework.core.AbstractDomainObject; import pt.ist.fenixframework.core.DomainObjectAllocator; import pt.ist.fenixframework.core.Externalization; import pt.ist.fenixframework.core.IdentityMap; import pt.ist.fenixframework.core.SharedIdentityMap; public class InfinispanBackEnd implements BackEnd { private static final Logger logger = LoggerFactory.getLogger(InfinispanBackEnd.class); public static final String BACKEND_NAME = "ispn"; private static final String DOMAIN_CACHE_NAME = "DomainCache"; private static final InfinispanBackEnd instance = new InfinispanBackEnd(); protected final InfinispanTransactionManager transactionManager; protected Cache<String, Object> domainCache; private InfinispanBackEnd() { this.transactionManager = new InfinispanTransactionManager(); } public static InfinispanBackEnd getInstance() { return instance; } @Override public String getName() { return BACKEND_NAME; } @Override public DomainRoot getDomainRoot() { return fromOid(OID.ROOT_OBJECT_ID); } @Override public <T extends DomainObject> T getDomainObject(String externalId) { return fromOid(new OID(externalId)); } @Override public TransactionManager getTransactionManager() { return this.transactionManager; } @Override public <T extends DomainObject> T fromOid(Object oid) { OID internalId = (OID)oid; if (logger.isTraceEnabled()) { logger.trace("fromOid(" + internalId.getFullId() + ")"); } IdentityMap cache = getIdentityMap(); AbstractDomainObject obj = cache.lookup(internalId); if (obj == null) { if (logger.isTraceEnabled()) { logger.trace("Object not found in IdentityMap: " + internalId.getFullId()); } obj = DomainObjectAllocator.allocateObject(internalId.getObjClass(), internalId); // cache object and return the canonical object obj = cache.cache(obj); } return (T) obj; } /** * Shuts down Infinispan's cache(s) and the(ir) manager(s) */ @Override public void shutdown() { // not sure whether is still safe, after a stop() to getCacheManager(), so I get it first EmbeddedCacheManager manager = domainCache.getCacheManager(); domainCache.stop(); manager.stop(); } protected void configInfinispan(InfinispanConfig config) throws Exception { setupCache(config); setupTxManager(config); config.waitForExpectedInitialNodes("backend-infinispan-init-barrier"); } private void setupCache(InfinispanConfig config) { long start = System.currentTimeMillis(); CacheContainer cc = null; try { cc = new DefaultCacheManager(config.getIspnConfigFile()); } catch (java.io.IOException ioe) { String message = "Error creating Infinispan cache manager with configuration file: " + config.getIspnConfigFile(); logger.error(message, ioe); throw new Error(message, ioe); } domainCache = cc.getCache(DOMAIN_CACHE_NAME); if (logger.isDebugEnabled()) { DateFormat df = new SimpleDateFormat("HH:mm.ss"); df.setTimeZone(TimeZone.getTimeZone("GMT")); logger.debug("Infinispan initialization took " + df.format(new Date(System.currentTimeMillis() - start))); } } private void setupTxManager(InfinispanConfig config) { transactionManager.setDelegateTxManager(domainCache.getAdvancedCache().getTransactionManager()); } protected IdentityMap getIdentityMap() { return SharedIdentityMap.getCache(); } /** * Store in Infinispan. This method supports null values. This method is used by the code * generated in the Domain Objects. */ public final void cachePut(String key, Object value) { domainCache.put(key, (value != null) ? value : Externalization.NULL_OBJECT); } /** * Reads from Infinispan a value with a given key. This method is used by the code generated in * the Domain Objects. */ public final <T> T cacheGet(String key) { Object obj = domainCache.get(key); return (T)(obj instanceof Externalization.NullClass ? null : obj); } /** * WARNING: This is a backend-specific method. It was added as an hack to enable some tests by * Algorithmica and will be removed later. The programmer should not use this method directly, * because by doing so the code becomes backend-dependent. */ @Deprecated public final Cache getInfinispanCache() { return this.domainCache; } }