/* // $Id: XmlaOlap4jNamedMemoryCache.java 455 2011-05-24 10:01:26Z jhyde $ // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. // Copyright (C) 2008-2011 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ package org.olap4j.driver.olap4ld.cache; import java.net.*; import java.util.*; import java.util.concurrent.*; import org.olap4j.driver.olap4ld.cache.XmlaOlap4jCache; import org.olap4j.driver.olap4ld.cache.XmlaOlap4jConcurrentMemoryCache; import org.olap4j.driver.olap4ld.cache.XmlaOlap4jInvalidStateException; import org.olap4j.driver.olap4ld.cache.XmlaOlap4jNamedMemoryCache; import org.olap4j.impl.Olap4jUtil; /** * <p>Implementation of the XMLA SOAP cache that places its cache entries * in memory for later use. It is thread safe and at static class level. * * <p>It supports cache sharing through the Name property. * * <p>All parameters are optional. * * <ul> * <li><b>NAME</b><br />A unique identifier which allows two connections * to share a same cache space. Setting this to an already existing cache * space will cause the cache manager to ignore other configuration properties, * such as eviction mode and so on. Not setting this property will * assign a random name to the cache space, thus creating a unique space.</li> * <li><b>SIZE</b><br />The number of entries to maintain in cache under * the given cache name.</li> * <li><b>TIMEOUT</b><br />The number of seconds to maintain entries in * cache before expiration.</li> * <li><b>MODE</b><br />Supported eviction modes are LIFO (last in first out), * FIFO (first in first out), LFU (least frequently used) and MFU * (most frequently used)</li> * </ul> * * @see XmlaOlap4jNamedMemoryCache.Property * @version $Id: XmlaOlap4jNamedMemoryCache.java 455 2011-05-24 10:01:26Z jhyde $ */ public class XmlaOlap4jNamedMemoryCache implements XmlaOlap4jCache { /** * <p>Thread safe hashmap which will be used to keep track of * the current caches. The unique ID is the URL. */ private static Map<String, XmlaOlap4jConcurrentMemoryCache> caches = null; /** * Properties which will be considered for configuration. * * <p>All parameters are optional. */ public static enum Property { /** * A unique identifier which allows two connections to share a same * cache space. Setting this to an already existing cache * space will cause the cache manager to ignore other configuration * properties, such as eviction mode and so on. Not setting this * property will assign a random name to the cache space, thus creating * a unique space. */ NAME("Name of a cache to create or to share."), /** * The number of entries to maintain in cache under * the given cache name. */ SIZE( "Maximum number of SOAP requests which will be cached under the " + "given cache name."), /** * The number of seconds to maintain * entries in cache before expiration. */ TIMEOUT( "Maximum TTL of SOAP requests which will be cached under the given " + "cache name."), /** * Eviction mode. Supported eviction modes are * LIFO (last in first out), FIFO (first in first out), * LFU (least frequently used) and MFU (most frequently used). */ MODE("Eviction mode to set to the given cache name."); /** * Creates a property. * * @param description Description of property */ Property(String description) { Olap4jUtil.discard(description); } } /** * Defines the supported eviction modes. */ public static enum Mode { /** Last-in, first-out. */ LIFO, /** First-in, first-out. */ FIFO, /** Least-frequently used. */ LFU, /** Most-frequently used. */ MFU } /** * Makes sure that the cache is not accessed before it is configured. */ private boolean initDone = false; /** * Default constructor which instantiates the concurrent hash map. */ public XmlaOlap4jNamedMemoryCache() { XmlaOlap4jNamedMemoryCache.initCaches(); } /** * Initializes the caches in a static and thread safe way. */ private static synchronized void initCaches() { if (caches == null) { caches = new ConcurrentHashMap< String, XmlaOlap4jConcurrentMemoryCache>(); } } // implement XmlaOlap4jCache public String setParameters( Map<String, String> config, Map<String, String> props) { String refId; // Make sure there's a name for the cache. Generate a // random one if needed. if (props.containsKey( XmlaOlap4jNamedMemoryCache.Property.NAME.name())) { refId = (String) props.get( XmlaOlap4jNamedMemoryCache.Property.NAME.name()); } else { refId = String.valueOf(UUID.randomUUID()); props.put(XmlaOlap4jNamedMemoryCache.Property.NAME.name(), refId); } // Wait for exclusive access to the caches synchronized (caches) { // Create a cache for this URL if it is not created yet if (!caches.containsKey( props.get( XmlaOlap4jNamedMemoryCache.Property.NAME.name()))) { caches.put( (String) props.get( XmlaOlap4jNamedMemoryCache.Property.NAME.name()), new XmlaOlap4jConcurrentMemoryCache(props)); } } // Mark this cache as inited. this.initDone = true; // Give back the reference id. return refId; } // implement XmlaOlap4jCache public byte[] get( String id, URL url, byte[] request) throws XmlaOlap4jInvalidStateException { this.validateState(); // Wait for exclusive access to the caches synchronized (caches) { if (caches.containsKey(id)) { return caches.get(id).get(url, request); } else { throw new XmlaOlap4jInvalidStateException(); } } } // implement XmlaOlap4jCache public void put( String id, URL url, byte[] request, byte[] response) throws XmlaOlap4jInvalidStateException { this.validateState(); // Wait for exclusive access to the caches synchronized (caches) { if (caches.containsKey(id)) { caches.get(id).put(url, request, response); } else { throw new XmlaOlap4jInvalidStateException(); } } } // implement XmlaOlap4jCache public void flushCache() { // Wait for exclusive access to the caches synchronized (caches) { caches.clear(); } } /** * Helper method to validate that the cache is initialized. * * @throws XmlaOlap4jInvalidStateException When the cache is not initialized. */ private void validateState() throws XmlaOlap4jInvalidStateException { if (!this.initDone) { throw new XmlaOlap4jInvalidStateException(); } } } // End XmlaOlap4jNamedMemoryCache.java