1 16 package org.apache.cocoon.components.store; 17 18 import org.apache.avalon.framework.activity.Disposable; 19 import org.apache.avalon.framework.component.ComponentException; 20 import org.apache.avalon.framework.component.ComponentManager; 21 import org.apache.avalon.framework.component.Composable; 22 import org.apache.avalon.framework.logger.AbstractLogEnabled; 23 import org.apache.avalon.framework.parameters.Parameters; 24 import org.apache.avalon.framework.parameters.ParameterException; 25 import org.apache.avalon.framework.parameters.Parameterizable; 26 import org.apache.avalon.framework.thread.ThreadSafe; 27 28 import org.apache.cocoon.util.ClassUtils; 29 import org.apache.cocoon.util.MRUBucketMap; 30 31 import java.io.IOException ; 32 import java.net.URLEncoder ; 33 import java.util.Enumeration ; 34 import java.util.NoSuchElementException ; 35 import java.util.Iterator ; 36 import java.util.Map ; 37 38 55 public final class MRUMemoryStore extends AbstractLogEnabled 56 implements Store, Parameterizable, Composable, Disposable, ThreadSafe { 57 58 private int maxobjects; 59 private boolean persistent; 60 protected MRUBucketMap cache; 61 private Store persistentStore; 62 private StoreJanitor storeJanitor; 63 private ComponentManager manager; 64 65 70 public void compose(ComponentManager manager) throws ComponentException { 71 this.manager = manager; 72 if (getLogger().isDebugEnabled()) { 73 getLogger().debug("Looking up " + Store.PERSISTENT_CACHE); 74 getLogger().debug("Looking up " + StoreJanitor.ROLE); 75 } 76 this.persistentStore = (Store)manager.lookup(Store.PERSISTENT_CACHE); 77 this.storeJanitor = (StoreJanitor)manager.lookup(StoreJanitor.ROLE); 78 } 79 80 92 public void parameterize(Parameters params) throws ParameterException { 93 this.maxobjects = params.getParameterAsInteger("maxobjects", 100); 94 this.persistent = params.getParameterAsBoolean("use-persistent-cache", false); 95 if ((this.maxobjects < 1)) { 96 throw new ParameterException("MRUMemoryStore maxobjects must be at least 1!"); 97 } 98 99 this.cache = new MRUBucketMap((int)(this.maxobjects * 1.2)); 100 this.storeJanitor.register(this); 101 } 102 103 106 public void dispose() { 107 if (this.manager != null) { 108 getLogger().debug("Disposing component!"); 109 110 if (this.storeJanitor != null) 111 this.storeJanitor.unregister(this); 112 this.manager.release(this.storeJanitor); 113 this.storeJanitor = null; 114 115 if (this.persistent) { 117 if (getLogger().isDebugEnabled()) { 118 getLogger().debug("Final cache size: " + this.cache.size()); 119 } 120 for (Iterator i = this.cache.keySet().iterator(); i.hasNext(); ) { 121 Object key = i.next(); 122 try { 123 Object value = this.cache.remove(key); 124 if(checkSerializable(value)) { 125 persistentStore.store(getFileName(key.toString()), 126 value); 127 } 128 } catch (IOException ioe) { 129 getLogger().error("Error in dispose()", ioe); 130 } 131 } 132 } 133 this.manager.release(this.persistentStore); 134 this.persistentStore = null; 135 } 136 137 this.manager = null; 138 } 139 140 148 public void store(Object key, Object value) { 149 this.hold(key,value); 150 } 151 152 160 public void hold(Object key, Object value) { 161 if (getLogger().isDebugEnabled()) { 162 getLogger().debug("Holding object in memory:"); 163 getLogger().debug(" key: " + key); 164 getLogger().debug(" value: " + value); 165 } 166 167 168 while (this.cache.size() >= this.maxobjects) { 169 170 this.free(); 171 } 172 173 174 this.cache.put(key, value); 175 } 176 177 183 public Object get(Object key) { 184 Object value = this.cache.get(key); 185 if (value != null) { 186 if (getLogger().isDebugEnabled()) { 187 getLogger().debug("Found key: " + key.toString()); 188 } 189 return value; 190 } 191 192 if (getLogger().isDebugEnabled()) { 193 getLogger().debug("NOT Found key: " + key.toString()); 194 } 195 196 197 if (this.persistent) { 198 value = this.persistentStore.get(getFileName(key.toString())); 199 if (value != null) { 200 try { 201 this.hold(key, value); 202 return value; 203 } catch (Exception e) { 204 getLogger().error("Error in hold()!", e); 205 return null; 206 } 207 } 208 } 209 210 return null; 211 } 212 213 218 public void remove(Object key) { 219 if (getLogger().isDebugEnabled()) { 220 getLogger().debug("Removing object from store"); 221 getLogger().debug(" key: " + key); 222 } 223 this.cache.remove(key); 224 if(this.persistent && key != null) { 225 this.persistentStore.remove(getFileName(key.toString())); 226 } 227 } 228 229 235 public boolean containsKey(Object key) { 236 return cache.containsKey(key) || (persistent && persistentStore.containsKey(key)); 237 } 238 239 244 public Enumeration keys() { 245 return new Enumeration () { 246 private Iterator i = cache.keySet().iterator(); 247 248 public boolean hasMoreElements() { 249 return i.hasNext(); 250 } 251 252 public Object nextElement() { 253 return i.next(); 254 } 255 }; 256 } 257 258 262 public int size() { 263 return this.cache.size(); 264 } 265 266 270 public void free() { 271 try { 272 if (this.cache.size() > 0) { 273 Map.Entry node = this.cache.removeLast(); 275 if (getLogger().isDebugEnabled()) { 276 getLogger().debug("Freeing cache."); 277 getLogger().debug(" key: " + node.getKey()); 278 getLogger().debug(" value: " + node.getValue()); 279 } 280 281 if (this.persistent) { 282 if(checkSerializable(node.getValue())) { 284 try { 285 this.persistentStore.store( 286 getFileName(node.getKey().toString()), node.getValue()); 287 } catch(Exception e) { 288 getLogger().error("Error storing object on fs", e); 289 } 290 } 291 } 292 } 293 } catch (NoSuchElementException e) { 294 getLogger().warn("Concurrency error in free()", e); 295 } catch (Exception e) { 296 getLogger().error("Error in free()", e); 297 } 298 } 299 300 306 private boolean checkSerializable(Object object) { 307 308 if (object == null) return false; 309 310 try { 311 String clazz = object.getClass().getName(); 312 if((clazz.equals("org.apache.cocoon.caching.CachedEventObject")) 313 || (clazz.equals("org.apache.cocoon.caching.CachedStreamObject")) 314 || (ClassUtils.implementsInterface(clazz, "org.apache.cocoon.caching.CacheValidity"))) { 315 return true; 316 } else { 317 return false; 318 } 319 } catch (Exception e) { 320 getLogger().error("Error in checkSerializable()!", e); 321 return false; 322 } 323 } 324 325 333 private String getFileName(String key) { 334 return URLEncoder.encode(key.toString()); 335 } 336 } 337 | Popular Tags |