Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.codename1.io;
import com.codename1.ui.Display;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* A cache map is essentially a hashtable that indexes entries based on age and is
* limited to a fixed size. Hence when an entry is placed into the cache map and the
* cache size needs to increase, the least referenced entry is removed.
* A cache hit is made both on fetching and putting, hence frequently fetched elements
* will never be removed from a sufficiently large cache.
* Cache can work purely in memory or swap data into storage based on user definitions.
* Notice that this class isn't threadsafe.
*
* @author Shai Almog
*/
public class CacheMap {
private int cacheSize = 10;
private Hashtable memoryCache = new Hashtable();
private Hashtable weakCache = new Hashtable();
private int storageCacheSize = 0;
private Vector storageCacheContentVec;
private String cachePrefix = "";
private boolean alwaysStore;
private int storageKey = -1;
private Vector getStorageCacheContent() {
if(storageCacheContentVec == null) {
storageCacheContentVec = (Vector)Storage.getInstance().readObject("$CACHE$Idx" + cachePrefix);
if(storageCacheContentVec == null) {
storageCacheContentVec = new Vector();
}
}
return storageCacheContentVec;
}
/**
* Default constructor
*/
public CacheMap() {
}
/**
* Creates a cache map with a prefix string
* @param prefix string to prepend to the cache entries in storage
*/
public CacheMap(String prefix) {
this.cachePrefix = prefix;
}
/**
* Indicates the size of the memory cache after which the cache won't grow further
* Size is indicated by number of elements stored and not by KB or similar benchmark!
*
* @return the cacheSize
*/
public int getCacheSize() {
return cacheSize;
}
/**
* Indicates the size of the memory cache after which the cache won't grow further
* Size is indicated by number of elements stored and not by KB or similar benchmark!
*
* @param cacheSize the cacheSize to set
*/
public void setCacheSize(int cacheSize) {
this.cacheSize = cacheSize;
}
/**
* Puts the given key/value pair in the cache
*
* @param key the key
* @param value the value
*/
public void put(Object key, Object value) {
if(cacheSize <= memoryCache.size()) {
// we need to find the oldest entry
Enumeration e = memoryCache.keys();
long oldest = System.currentTimeMillis();
Object oldestKey = null;
Object[] oldestValue = null;
while(e.hasMoreElements()) {
Object currentKey = e.nextElement();
Object[] currentValue = (Object[])memoryCache.get(currentKey);
long currentAge = ((Long)currentValue[0]).longValue();
if(currentAge <= oldest || oldestValue == null) {
oldest = currentAge;
oldestKey = currentKey;
oldestValue = currentValue;
}
}
placeInStorageCache(oldestKey, oldest, oldestValue[1]);
weakCache.put(oldestKey, Display.getInstance().createSoftWeakRef(oldestValue[1]));
memoryCache.remove(oldestKey);
}
long lastAccess = System.currentTimeMillis();
memoryCache.put(key, new Object[]{new Long(lastAccess), value});
if(alwaysStore) {
placeInStorageCache(key, lastAccess, value);
}
}
/**
* Deletes a cached entry
*
* @param key entry to remove from the cache
*/
public void delete(Object key) {
memoryCache.remove(key);
weakCache.remove(key);
Vector storageCacheContent = getStorageCacheContent();
int s = storageCacheContent.size();
for(int iter = 0 ; iter < s ; iter++) {
Object[] obj = (Object[])storageCacheContent.elementAt(iter);
if(obj[1].equals(key)) {
Storage.getInstance().deleteStorageFile("$CACHE$" + cachePrefix + key.toString());
obj[0] = new Long(Long.MIN_VALUE);
obj[1] = obj[0];
Storage.getInstance().writeObject("$CACHE$Idx" + cachePrefix, storageCacheContent);
return;
}
}
}
/**
* Returns the object matching the given key
*
* @param key key object
* @return value from a previous put or null
*/
public Object get(Object key) {
Object[] o = (Object[])memoryCache.get(key);
if(o != null) {
return o[1];
}
Object ref = weakCache.get(key);
if(ref != null) {
ref = Display.getInstance().extractHardRef(ref);
if(ref != null) {
// cache hit! Promote it to the hard cache again
put(key, ref);
return ref;
}
}
if(storageCacheSize > 0) {
Vector storageCacheContent = getStorageCacheContent();
for(int iter = 0 ; iter < storageCacheContent.size() ; iter++) {
Object[] obj = (Object[])storageCacheContent.elementAt(iter);
if(obj[1].equals(key)) {
// place the object back into the memory cache and return the value
Vector v = (Vector)Storage.getInstance().readObject("$CACHE$" + cachePrefix + key.toString());
if(v != null) {
Object val = v.elementAt(0);
put(key, val);
return val;
}
return null;
}
}
}
return null;
}
/**
* Clears the caches for this cache object
*/
public void clearAllCache() {
clearMemoryCache();
clearStorageCache();
}
/**
* Clears the memory cache
*/
public void clearMemoryCache() {
memoryCache.clear();
weakCache.clear();
}
private void placeInStorageCache(Object key, long lastAccessed, Object value) {
if(storageCacheSize < 1) {
return;
}
Vector storageCacheContent = getStorageCacheContent();
int vecSize = storageCacheContent.size();
// find the best place
for(int iter = 0 ; iter < vecSize ; iter++) {
Object[] index = (Object[])storageCacheContent.elementAt(iter);
Object indexKey = index[1];
if(indexKey.equals(key)) {
// already in storage just update the data
placeInStorageCache(iter, key, lastAccessed, value);
return;
}
}
if(storageCacheContent.size() < storageCacheSize) {
placeInStorageCache(storageCacheContent.size(), key, lastAccessed, value);
} else {
long smallest = Long.MAX_VALUE;
int offset = 0;
// find the best place
for(int iter = 0 ; iter < vecSize ; iter++) {
Object[] index = (Object[])storageCacheContent.elementAt(iter);
long current = ((Long)index[0]).longValue();
if(smallest > current) {
smallest = current;
offset = iter;
}
}
placeInStorageCache(offset, key, lastAccessed, value);
}
}
private void placeInStorageCache(int offset, Object key, long lastAccessed, Object value) {
Vector v = new Vector();
v.addElement(value);
Long l = new Long(lastAccessed);
v.addElement(l);
v.addElement(key);
Storage.getInstance().writeObject("$CACHE$" + cachePrefix + key.toString(), v);
Vector storageCacheContent = getStorageCacheContent();
if(storageCacheContent.size() > offset) {
storageCacheContent.setElementAt(new Object[] {l, key}, offset);
} else {
storageCacheContent.insertElementAt(new Object[] {l, key}, offset);
}
Storage.getInstance().writeObject("$CACHE$Idx" + cachePrefix, storageCacheContent);
}
/**
* Returns the keys for all the objects currently in cache, this is useful
* to traverse all the objects and refresh them without actually deleting
* the cache and fetching them from scratch.
* Important this vector is a copy of a current state, keys might
* not exist anymore or might change, others might be added in the interim.
*
* @return a vector containing a snapshot of the current elements within the
* cache.
*/
public Vector getKeysInCache() {
Vector r = new Vector();
Enumeration en = memoryCache.keys();
while(en.hasMoreElements()) {
r.addElement(en.nextElement());
}
Vector storageCacheContent = getStorageCacheContent();
for(int iter = 0 ; iter < storageCacheContent.size() ; iter++) {
Object[] o = (Object[])storageCacheContent.elementAt(iter);
if(!r.contains(o[1])) {
r.addElement(o[1]);
}
}
return r;
}
private Vector fetchFromStorageCache(int offset) {
Vector v = getStorageCacheContent();
Object[] arr = (Object[])v.elementAt(offset);
return (Vector)Storage.getInstance().readObject("$CACHE$" + cachePrefix + arr[1].toString());
}
/**
* Clears the storage cache
*/
public void clearStorageCache() {
if(storageCacheSize > 0) {
Vector v = getStorageCacheContent();
int s = v.size();
for(int iter = 0 ; iter < s ; iter++) {
Object[] arr = (Object[])v.elementAt(iter);
Storage.getInstance().deleteStorageFile("$CACHE$" + cachePrefix + arr[iter].toString());
}
Storage.getInstance().deleteStorageFile("$CACHE$Idx" + cachePrefix);
storageCacheContentVec = new Vector();
}
}
/**
* Indicates the size of the storage cache after which the cache won't grow further
* Size is indicated by number of elements stored and not by KB or similar benchmark!
*
* @return the storageCacheSize
*/
public int getStorageCacheSize() {
return storageCacheSize;
}
/**
* Indicates the size of the storage cache after which the cache won't grow further
* Size is indicated by number of elements stored and not by KB or similar benchmark!
*
* @param storageCacheSize the storageCacheSize to set
*/
public void setStorageCacheSize(int storageCacheSize) {
this.storageCacheSize = storageCacheSize;
/*for(int iter = 0 ; iter < storageCacheSize ; iter++) {
Vector v = fetchFromStorageCache(iter);
if(v != null) {
Object o = new Object[] {v.elementAt(1), v.elementAt(2)};
Vector storageCacheContent = getStorageCacheContent();
if(iter >= storageCacheContent.size()) {
storageCacheContent.addElement(o);
} else {
storageCacheContent.insertElementAt(o, iter);
}
}
}*/
if(storageCacheSize == 0) {
alwaysStore = false;
}
}
/**
* A prefix prepended to storage entries to differentiate them
* @return the cachePrefix
*/
public String getCachePrefix() {
return cachePrefix;
}
/**
* A prefix prepended to storage entries to differentiate them
* @param cachePrefix the cachePrefix to set
*/
public void setCachePrefix(String cachePrefix) {
this.cachePrefix = cachePrefix;
}
/**
* When set to true indicates that all entries should be persisted to storage
* for a constantly persisting cache
* @return the alwaysStore
*/
public boolean isAlwaysStore() {
return alwaysStore;
}
/**
* When set to true indicates that all entries should be persisted to storage
* for a constantly persisting cache
* @param alwaysStore the alwaysStore to set
*/
public void setAlwaysStore(boolean alwaysStore) {
this.alwaysStore = alwaysStore;
}
}