package lucee.runtime.type.scope.storage;
import java.sql.SQLException;
import lucee.commons.collection.MapPro;
import lucee.commons.io.log.Log;
import lucee.commons.lang.ExceptionUtil;
import lucee.runtime.PageContext;
import lucee.runtime.PageContextImpl;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.converter.JavaConverter;
import lucee.runtime.db.DataSource;
import lucee.runtime.db.DatasourceConnection;
import lucee.runtime.db.DatasourceConnectionPool;
import lucee.runtime.debug.DebuggerUtil;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ApplicationException;
import lucee.runtime.exp.PageException;
import lucee.runtime.op.Caster;
import lucee.runtime.type.Query;
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.scope.ScopeContext;
import lucee.runtime.type.scope.storage.db.SQLExecutionFactory;
import lucee.runtime.type.scope.storage.db.SQLExecutor;
import lucee.runtime.type.util.KeyConstants;
public class IKHandlerDatasource implements IKHandler {
public static final String PREFIX = "cf";
@Override
public IKStorageValue loadData(PageContext pc, String appName, String name, String strType,
int type, Log log) throws PageException {
ConfigImpl config = (ConfigImpl)ThreadLocalPageContext.getConfig(pc);
DatasourceConnectionPool pool = config.getDatasourceConnectionPool();
DatasourceConnection dc=pool.getDatasourceConnection(config,pc.getDataSource(name),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 Lucee administrator.");
query = executor.select(config,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 && config.debug()) {
boolean debugUsage=DebuggerUtil.debugQueryUsage(pc,query);
pc.getDebugger().addQuery(debugUsage?query:null,name,"",query.getSql(),query.getRecordcount(),((PageContextImpl)pc).getCurrentPageSource(null),query.getExecutionTime());
}
boolean _isNew = query.getRecordcount()==0;
if(_isNew) {
ScopeContext.info(log,"create new "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID()+" in datasource ["+name+"]");
return null;
}
String str=Caster.toString(query.get(KeyConstants._data));
if(str.startsWith("struct:")) return null;
try{
IKStorageValue data=(IKStorageValue) JavaConverter.deserialize(str);
ScopeContext.info(log,"load existing data from ["+name+"."+PREFIX+"_"+strType+"_data] to create "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID());
return data;
}
catch(Exception e) {
throw Caster.toPageException(e);
}
}
@Override
public void store(IKStorageScopeSupport storageScope, PageContext pc, String appName, String name, String cfid,
MapPro<Key, IKStorageScopeItem> data, Log log) {
DatasourceConnection dc = null;
ConfigImpl ci = (ConfigImpl)ThreadLocalPageContext.getConfig(pc);
DatasourceConnectionPool pool = ci.getDatasourceConnectionPool();
try {
pc = ThreadLocalPageContext.get(pc);
DataSource ds;
if(pc!=null) ds=pc.getDataSource(name);
else ds=ci.getDataSource(name);
dc=pool.getDatasourceConnection(null,ds,null,null);
SQLExecutor executor=SQLExecutionFactory.getInstance(dc);
IKStorageValue existingVal = loadData(pc, appName,name, storageScope.getTypeAsString(), storageScope.getType(), log);
IKStorageValue sv = new IKStorageValue(IKStorageScopeSupport.prepareToStore(data,existingVal,storageScope.lastModified()));
executor.update(ci, cfid,appName, dc, storageScope.getType(), sv, storageScope.getTimeSpan(),log);
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
ScopeContext.error(log, t);
}
finally {
if(dc!=null) pool.releaseDatasourceConnection(dc);
}
}
@Override
public void unstore(IKStorageScopeSupport storageScope, PageContext pc, String appName, String name, String cfid, Log log) {
ConfigImpl ci=(ConfigImpl) ThreadLocalPageContext.getConfig(pc);
DatasourceConnection dc = null;
DatasourceConnectionPool pool = ci.getDatasourceConnectionPool();
try {
pc = ThreadLocalPageContext.get(pc);// FUTURE change method interface
DataSource ds;
if(pc!=null) ds=pc.getDataSource(name);
else ds=ci.getDataSource(name);
dc=pool.getDatasourceConnection(null,ds,null,null);
SQLExecutor executor=SQLExecutionFactory.getInstance(dc);
executor.delete(ci, cfid,appName, dc, storageScope.getType(),log);
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
ScopeContext.error(log, t);
}
finally {
if(dc!=null) pool.releaseDatasourceConnection(dc);
}
}
@Override
public String getType() {
return "Datasource";
}
}