package railo.commons.io.res.type.cache;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import railo.commons.io.cache.Cache;
import railo.commons.io.cache.CacheEntry;
import railo.commons.io.res.Resource;
import railo.commons.io.res.ResourceProvider;
import railo.commons.io.res.Resources;
import railo.commons.io.res.util.ResourceLockImpl;
import railo.commons.io.res.util.ResourceUtil;
import railo.commons.lang.StringUtil;
import railo.runtime.cache.ram.RamCache;
import railo.runtime.config.ConfigImpl;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.functions.cache.Util;
import railo.runtime.op.Caster;
import railo.runtime.op.Constants;
import railo.runtime.type.Struct;
/**
* Resource Provider for ram resource
*/
public final class CacheResourceProvider implements ResourceProvider {
private String scheme="ram";
boolean caseSensitive=true;
private long lockTimeout=1000;
private ResourceLockImpl lock=new ResourceLockImpl(lockTimeout,caseSensitive);
private Map arguments;
private final Cache DEFAULT_CACHE=new RamCache();
private Set<Integer> inits=new HashSet<Integer>();
//private Config config;
/**
* initalize ram resource
* @param scheme
* @param arguments
* @return RamResource
*/
public ResourceProvider init(String scheme,Map arguments) {
if(!StringUtil.isEmpty(scheme))this.scheme=scheme;
if(arguments!=null) {
this.arguments=arguments;
Object oCaseSensitive= arguments.get("case-sensitive");
if(oCaseSensitive!=null) {
caseSensitive=Caster.toBooleanValue(oCaseSensitive,true);
}
// lock-timeout
Object oTimeout = arguments.get("lock-timeout");
if(oTimeout!=null) {
lockTimeout=Caster.toLongValue(oTimeout,lockTimeout);
}
}
lock.setLockTimeout(lockTimeout);
lock.setCaseSensitive(caseSensitive);
return this;
}
@Override
public Resource getResource(String path) {
path=ResourceUtil.removeScheme(scheme,path);
if(!StringUtil.startsWith(path,'/'))path="/"+path;
return new CacheResource(this,path);
}
/**
* returns core for this path if exists, otherwise return null
* @param path
* @return core or null
*/
CacheResourceCore getCore(String path,String name) {
Object obj = getCache().getValue(toKey(path,name),null);
if(obj instanceof CacheResourceCore) return (CacheResourceCore) obj;
return null;
}
void touch(String path,String name) {
Cache cache = getCache();
CacheEntry ce = cache.getCacheEntry(toKey(path,name),null);
if(ce!=null){
cache.put(ce.getKey(), ce.getValue(), ce.idleTimeSpan(), ce.liveTimeSpan());
}
}
Struct getMeta(String path,String name) {
CacheEntry ce = getCache().getCacheEntry(toKey(path,name),null);
if(ce!=null) return ce.getCustomInfo();
return null;
}
String[] getChildNames(String path) throws IOException {
List list = getCache().values(new ChildrenFilter(path));
String[] arr = new String[list.size()];
Iterator it = list.iterator();
int index=0;
while(it.hasNext()){
arr[index++]=((CacheResourceCore) it.next()).getName();
}
// TODO remove none CacheResourceCore elements
return arr;
}
/*CacheResourceCore[] getChildren(String path) {
List list = getCache().values(new ChildrenFilter(path));
CacheResourceCore[] arr = new CacheResourceCore[list.size()];
Iterator it = list.iterator();
int index=0;
while(it.hasNext()){
arr[index++]=(CacheResourceCore) it.next();
}
// TODO remove none CacheResourceCore elements
return arr;
}*/
/**
* create a new core
* @param path
* @param type
* @return created core
* @throws IOException
*/
CacheResourceCore createCore(String path, String name, int type) throws IOException {
CacheResourceCore value = new CacheResourceCore(type,path,name);
getCache().put(toKey(path,name),value,null,null);
return value;
}
void removeCore(String path, String name) throws IOException {
getCache().remove(toKey(path,name));
}
@Override
public String getScheme() {
return scheme;
}
@Override
public void setResources(Resources resources) {
//this.resources=resources;
}
@Override
public void lock(Resource res) throws IOException {
lock.lock(res);
}
@Override
public void unlock(Resource res) {
lock.unlock(res);
}
@Override
public void read(Resource res) throws IOException {
lock.read(res);
}
@Override
public boolean isAttributesSupported() {
return true;
}
@Override
public boolean isCaseSensitive() {
return caseSensitive;
}
@Override
public boolean isModeSupported() {
return true;
}
@Override
public Map getArguments() {
return arguments;
}
private Cache getCache() {
Cache c = Util.getDefault(ThreadLocalPageContext.get(),ConfigImpl.CACHE_DEFAULT_RESOURCE,DEFAULT_CACHE);
if(!inits.contains(c.hashCode())){
String k = toKey("null","");
if(!c.contains(k)) {
CacheResourceCore value = new CacheResourceCore(CacheResourceCore.TYPE_DIRECTORY,null,"");
c.put(k,value,Constants.LONG_ZERO,Constants.LONG_ZERO);
}
inits.add(c.hashCode());
}
return c;
}
private String toKey(String path, String name) {
if(caseSensitive) return path+":"+name;
return (path+":"+name).toLowerCase();
}
}