001 /* 002 // $Id: XmlaOlap4jNamedMemoryCache.java 253 2009-06-30 03:06:10Z jhyde $ 003 // This software is subject to the terms of the Eclipse Public License v1.0 004 // Agreement, available at the following URL: 005 // http://www.eclipse.org/legal/epl-v10.html. 006 // Copyright (C) 2008-2009 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package org.olap4j.driver.xmla.cache; 011 012 import java.net.*; 013 import java.util.*; 014 import java.util.concurrent.*; 015 016 import org.olap4j.impl.Olap4jUtil; 017 018 /** 019 * <p>Implementation of the XMLA SOAP cache that places its cache entries 020 * in memory for later use. It is thread safe and at static class level. 021 * 022 * <p>It supports cache sharing through the Name property. 023 * 024 * <p>All parameters are optional. 025 * 026 * <ul> 027 * <li><b>Name</b><br />A unique identifier which allows two connections 028 * to share a same cache space. Setting this to an already existing cache 029 * space will cause the cache manager to ignore other configuration properties, 030 * such as eviction mode and so on. Not setting this property will 031 * assign a random name to the cache space, thus creating a unique space.</li> 032 * <li><b>Size</b><br />The number of entries to maintain in cache under 033 * the given cache name.</li> 034 * <li><b>Timeout</b><br />The number of seconds to maintain entries in 035 * cache before expiration.</li> 036 * <li><b>Mode</b><br />Supported eviction modes are LIFO (last in first out), 037 * FIFO (first in first out), LFU (least frequently used) and MFU 038 * (most frequently used)</li> 039 * </ul> 040 * 041 * @see XmlaOlap4jNamedMemoryCache.Property 042 * @version $Id: XmlaOlap4jNamedMemoryCache.java 253 2009-06-30 03:06:10Z jhyde $ 043 */ 044 public class XmlaOlap4jNamedMemoryCache implements XmlaOlap4jCache { 045 046 /** 047 * <p>Thread safe hashmap which will be used to keep track of 048 * the current caches. The unique ID is the URL. 049 */ 050 private static Map<String, XmlaOlap4jConcurrentMemoryCache> caches = null; 051 052 /** 053 * Properties which will be considered for configuration. 054 * 055 * <p>All parameters are optional. 056 */ 057 public static enum Property { 058 /** 059 * A unique identifier which allows two connections to share a same 060 * cache space. Setting this to an already existing cache 061 * space will cause the cache manager to ignore other configuration 062 * properties, such as eviction mode and so on. Not setting this 063 * property will assign a random name to the cache space, thus creating 064 * a unique space. 065 */ 066 Name("Name of a cache to create or to share."), 067 068 /** 069 * The number of entries to maintain in cache under 070 * the given cache name. 071 */ 072 Size( 073 "Maximum number of SOAP requests which will be cached under the " 074 + "given cache name."), 075 076 /** 077 * The number of seconds to maintain 078 * entries in cache before expiration. 079 */ 080 Timeout( 081 "Maximum TTL of SOAP requests which will be cached under the given " 082 + "cache name."), 083 084 /** 085 * Eviction mode. Supported eviction modes are 086 * LIFO (last in first out), FIFO (first in first out), 087 * LFU (least frequently used) and MFU (most frequently used). 088 */ 089 Mode("Eviction mode to set to the given cache name."); 090 091 /** 092 * Creates a property. 093 * 094 * @param description Description of property 095 */ 096 Property(String description) { 097 Olap4jUtil.discard(description); 098 } 099 } 100 101 102 /** 103 * Defines the supported eviction modes. 104 */ 105 public static enum Mode { 106 /** Last-in, first-out. */ 107 LIFO, 108 /** First-in, first-out. */ 109 FIFO, 110 /** Least-frequently used. */ 111 LFU, 112 /** Most-frequently used. */ 113 MFU 114 } 115 116 117 /** 118 * Makes sure that the cache is not accessed before it is configured. 119 */ 120 private boolean initDone = false; 121 122 123 /** 124 * Default constructor which instantiates the concurrent hash map. 125 */ 126 public XmlaOlap4jNamedMemoryCache() { 127 XmlaOlap4jNamedMemoryCache.initCaches(); 128 } 129 130 131 /** 132 * Initializes the caches in a static and thread safe way. 133 */ 134 private static synchronized void initCaches() { 135 if (caches == null) { 136 caches = 137 new ConcurrentHashMap< 138 String, XmlaOlap4jConcurrentMemoryCache>(); 139 } 140 } 141 142 // implement XmlaOlap4jCache 143 public String setParameters( 144 Map<String, String> config, 145 Map<String, String> props) 146 { 147 String refId; 148 149 // Make sure there's a name for the cache. Generate a 150 // random one if needed. 151 if (props.containsKey( 152 XmlaOlap4jNamedMemoryCache.Property.Name.name())) 153 { 154 refId = (String)props.get( 155 XmlaOlap4jNamedMemoryCache.Property.Name.name()); 156 } else { 157 refId = String.valueOf(UUID.randomUUID()); 158 props.put(XmlaOlap4jNamedMemoryCache.Property.Name.name(), refId); 159 } 160 161 162 // Wait for exclusive access to the caches 163 synchronized (caches) { 164 // Create a cache for this URL if it is not created yet 165 if (!caches.containsKey( 166 props.get( 167 XmlaOlap4jNamedMemoryCache.Property.Name.name()))) 168 { 169 caches.put( 170 (String) props.get( 171 XmlaOlap4jNamedMemoryCache.Property.Name.name()), 172 new XmlaOlap4jConcurrentMemoryCache(props)); 173 } 174 } 175 176 // Mark this cache as inited. 177 this.initDone = true; 178 179 // Give back the reference id. 180 return refId; 181 } 182 183 184 // implement XmlaOlap4jCache 185 public byte[] get( 186 String id, 187 URL url, 188 byte[] request) 189 throws XmlaOlap4jInvalidStateException 190 { 191 this.validateState(); 192 193 // Wait for exclusive access to the caches 194 synchronized (caches) { 195 if (caches.containsKey(id)) { 196 return caches.get(id).get(url, request); 197 } else { 198 throw new RuntimeException( 199 "There are no configured caches of this name yet configured."); 200 } 201 } 202 } 203 204 205 // implement XmlaOlap4jCache 206 public void put( 207 String id, 208 URL url, 209 byte[] request, 210 byte[] response) 211 throws XmlaOlap4jInvalidStateException 212 { 213 this.validateState(); 214 215 // Wait for exclusive access to the caches 216 synchronized (caches) { 217 if (caches.containsKey(id)) { 218 caches.get(id).put(url, request, response); 219 } else { 220 throw new RuntimeException( 221 "There are no configured caches of this name yet " 222 + "configured."); 223 } 224 } 225 } 226 227 // implement XmlaOlap4jCache 228 public void flushCache() { 229 // Wait for exclusive access to the caches 230 synchronized (caches) { 231 caches.clear(); 232 } 233 } 234 235 /** 236 * Helper method to validate that the cache is initialized. 237 * 238 * @throws XmlaOlap4jInvalidStateException When the cache is not initialized. 239 */ 240 private void validateState() throws XmlaOlap4jInvalidStateException { 241 if (!this.initDone) { 242 throw new XmlaOlap4jInvalidStateException(); 243 } 244 } 245 } 246 247 // End XmlaOlap4jNamedMemoryCache.java