package railo.runtime.type.scope.storage;
import java.sql.SQLException;
import railo.commons.io.log.Log;
import railo.runtime.PageContext;
import railo.runtime.PageContextImpl;
import railo.runtime.config.Config;
import railo.runtime.config.ConfigImpl;
import railo.runtime.db.DataSource;
import railo.runtime.db.DatasourceConnection;
import railo.runtime.db.DatasourceConnectionPool;
import railo.runtime.debug.DebuggerPro;
import railo.runtime.debug.DebuggerUtil;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.type.Query;
import railo.runtime.type.Struct;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.dt.DateTimeImpl;
import railo.runtime.type.scope.ScopeContext;
import railo.runtime.type.scope.storage.db.SQLExecutionFactory;
import railo.runtime.type.scope.storage.db.SQLExecutor;
import railo.runtime.type.util.KeyConstants;
/**
* client scope that store it's data in a datasource
*/
public abstract class StorageScopeDatasource extends StorageScopeImpl {
private static final long serialVersionUID = 239179599401918216L;
public static final String PREFIX = "cf";
private String datasourceName;
private String appName;
private String cfid;
/**
* Constructor of the class
* @param pc
* @param name
* @param sct
* @param b
*/
protected StorageScopeDatasource(PageContext pc,String datasourceName, String strType,int type,Struct sct) {
super(
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.datasourceName=datasourceName;
appName=pc.getApplicationContext().getName();
cfid=pc.getCFID();
}
/**
* Constructor of the class, clone existing
* @param other
*/
protected StorageScopeDatasource(StorageScopeDatasource other,boolean deepCopy) {
super(other,deepCopy);
this.datasourceName=other.datasourceName;
}
private static DateTime doNowIfNull(PageContext pc,DateTime dt) {
if(dt==null)return new DateTimeImpl(pc.getConfig());
return dt;
}
protected static Struct _loadData(PageContext pc, String datasourceName,String strType,int type, Log log, boolean mxStyle) throws PageException {
ConfigImpl config = (ConfigImpl)pc.getConfig();
DatasourceConnectionPool pool = config.getDatasourceConnectionPool();
DatasourceConnection dc=pool.getDatasourceConnection(pc,((PageContextImpl)pc).getDataSource(datasourceName),null,null);
SQLExecutor executor=SQLExecutionFactory.getInstance(dc);
Query query;
try {
if(!dc.getDatasource().isStorage())
throw new ApplicationException("storage usage for this datasource is disabled, you can enable this in the railo administrator.");
query = executor.select(pc.getConfig(),pc.getCFID(),pc.getApplicationContext().getName(), dc, type,log, true);
}
catch (SQLException se) {
throw Caster.toPageException(se);
}
finally {
if(dc!=null) pool.releaseDatasourceConnection(dc);
}
if(query!=null && pc.getConfig().debug()) {
boolean debugUsage=DebuggerUtil.debugQueryUsage(pc,query);
((DebuggerPro)pc.getDebugger()).addQuery(debugUsage?query:null,datasourceName,"",query.getSql(),query.getRecordcount(),pc.getCurrentPageSource(),query.getExecutionTime());
}
boolean _isNew = query.getRecordcount()==0;
if(_isNew) {
ScopeContext.info(log,"create new "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID()+" in datasource ["+datasourceName+"]");
return null;
}
String str=Caster.toString(query.get(KeyConstants._data));
if(mxStyle) return null;
Struct s = (Struct)pc.evaluate(str);
ScopeContext.info(log,"load existing data from ["+datasourceName+"."+PREFIX+"_"+strType+"_data] to create "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID());
return s;
}
@Override
public void touchAfterRequest(PageContext pc) {
setTimeSpan(pc);
super.touchAfterRequest(pc);
store(pc.getConfig());
}
public void store(Config config) {
//if(!super.hasContent()) return;
DatasourceConnection dc = null;
ConfigImpl ci = (ConfigImpl)config;
DatasourceConnectionPool pool = ci.getDatasourceConnectionPool();
Log log=((ConfigImpl)config).getScopeLogger();
try {
PageContext pc = ThreadLocalPageContext.get();// FUTURE change method interface
DataSource ds;
if(pc!=null) ds=((PageContextImpl)pc).getDataSource(datasourceName);
else ds=config.getDataSource(datasourceName);
dc=pool.getDatasourceConnection(null,ds,null,null);
SQLExecutor executor=SQLExecutionFactory.getInstance(dc);
executor.update(config, cfid,appName, dc, getType(), sct,getTimeSpan(),log);
}
catch (Throwable t) {
ScopeContext.error(log, t);
}
finally {
if(dc!=null) pool.releaseDatasourceConnection(dc);
}
}
public void unstore(Config config) {
ConfigImpl ci=(ConfigImpl) config;
DatasourceConnection dc = null;
DatasourceConnectionPool pool = ci.getDatasourceConnectionPool();
Log log=((ConfigImpl)config).getScopeLogger();
try {
PageContext pc = ThreadLocalPageContext.get();// FUTURE change method interface
DataSource ds;
if(pc!=null) ds=((PageContextImpl)pc).getDataSource(datasourceName);
else ds=config.getDataSource(datasourceName);
dc=pool.getDatasourceConnection(null,ds,null,null);
SQLExecutor executor=SQLExecutionFactory.getInstance(dc);
executor.delete(config, cfid,appName, dc, getType(),log);
}
catch (Throwable t) {
ScopeContext.error(log, t);
}
finally {
if(dc!=null) pool.releaseDatasourceConnection(dc);
}
}
@Override
public void touchBeforeRequest(PageContext pc) {
setTimeSpan(pc);
super.touchBeforeRequest(pc);
}
@Override
public String getStorageType() {
return "Datasource";
}
/**
* @return the datasourceName
*/
public String getDatasourceName() {
return datasourceName;
}
}