package railo.runtime.type.scope.storage;
import railo.commons.io.IOUtil;
import railo.commons.io.log.Log;
import railo.commons.io.res.Resource;
import railo.commons.io.res.util.ResourceUtil;
import railo.commons.lang.StringUtil;
import railo.runtime.PageContext;
import railo.runtime.config.Config;
import railo.runtime.config.ConfigImpl;
import railo.runtime.config.ConfigWeb;
import railo.runtime.converter.ScriptConverter;
import railo.runtime.interpreter.CFMLExpressionInterpreter;
import railo.runtime.op.Caster;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.dt.DateTimeImpl;
import railo.runtime.type.scope.ScopeContext;
/**
* client scope that store it's data in a resource
*/
public abstract class StorageScopeFile extends StorageScopeImpl {
private static final long serialVersionUID = -7519591903822909934L;
public static final String STORAGE_TYPE = "File";
private static ScriptConverter serializer=new ScriptConverter();
protected static CFMLExpressionInterpreter evaluator=new CFMLExpressionInterpreter();
private Resource res;
/**
* Constructor of the class
* @param pc
* @param name
* @param sct
*/
protected StorageScopeFile(PageContext pc,Resource res,String strType,int type,Struct sct) {
super(
sct==null?(sct=new StructImpl()):sct,
doNowIfNull(pc,Caster.toDate(sct.get(TIMECREATED,null),false,pc.getTimeZone(),null)),
doNowIfNull(pc,Caster.toDate(sct.get(LASTVISIT,null),false,pc.getTimeZone(),null)),
-1,
type==SCOPE_CLIENT?Caster.toIntValue(sct.get(HITCOUNT,"1"),1):0,
strType,type);
this.res =res;// pc.getConfig().getClientScopeDir().getRealResource(name+"-"+pc.getCFID()+".script");
}
private static DateTime doNowIfNull(PageContext pc,DateTime dt) {
if(dt==null)return new DateTimeImpl(pc.getConfig());
return dt;
}
/**
* Constructor of the class, clone existing
* @param other
*/
protected StorageScopeFile(StorageScopeFile other,boolean deepCopy) {
super(other,deepCopy);
this.res=other.res;
}
@Override
public void touchBeforeRequest(PageContext pc) {
setTimeSpan(pc);
super.touchBeforeRequest(pc);
}
@Override
public void touchAfterRequest(PageContext pc) {
setTimeSpan(pc);
super.touchAfterRequest(pc);
store(pc.getConfig());
}
@Override
public void store(Config config) {
//if(!super.hasContent()) return;
try {
if(!res.exists())ResourceUtil.createFileEL(res, true);
IOUtil.write(res, (getTimeSpan()+System.currentTimeMillis())+":"+serializer.serializeStruct(sct, ignoreSet), "UTF-8", false);
}
catch (Throwable t) {}
}
protected static Struct _loadData(PageContext pc,Resource res, Log log) {
if(res.exists()) {
try {
String str=IOUtil.toString(res,"UTF-8");
int index=str.indexOf(':');
if(index!=-1){
long expires=Caster.toLongValue(str.substring(0,index),-1L);
// check is for backward compatibility, old files have no expires date inside. they do ot expire
if(expires!=-1) {
str=str.substring(index+1);
/*if(checkExpires && expires<System.currentTimeMillis()){
print.o("expired("+new Date(expires)+"):"+res);
return null;
}
else {
str=str.substring(index+1);
print.o("not expired("+new Date(expires)+"):"+res);
print.o(str);
}*/
}
}
Struct s = (Struct) evaluator.interpret(pc,str);
ScopeContext.info(log,"load existing file storage ["+res+"]");
return s;
}
catch (Throwable t) {
ScopeContext.error(log, t);
}
}
ScopeContext.info(log,"create new file storage ["+res+"]");
return null;
}
public void unstore(Config config) {
try {
if(!res.exists())return;
res.remove(true);
}
catch (Throwable t) {}
}
protected static Resource _loadResource(ConfigWeb config, int type,String name, String cfid) {
ConfigImpl ci = (ConfigImpl)config;
Resource dir= type==SCOPE_CLIENT?ci.getClientScopeDir():ci.getSessionScopeDir();
return dir.getRealResource(getFolderName(name,cfid,true));
}
/**
* return a folder name that match given input
* @param name
* @param cfid
* @param addExtension
* @return
*/
public static String getFolderName(String name, String cfid,boolean addExtension) {
if(addExtension) return getFolderName(name, cfid, false)+".scpt";
if(!StringUtil.isEmpty(name))
name=encode(name);//StringUtil.toVariableName(StringUtil.toLowerCase(name));
else
name="__empty__";
return name+"/"+cfid.substring(0,2)+"/"+cfid.substring(2);
}
@Override
public String getStorageType() {
return STORAGE_TYPE;
}
}