/** * Copyright (c) 2014, the Railo Company Ltd. * Copyright (c) 2015, Lucee Assosication Switzerland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ package lucee.runtime.type.scope.storage; import java.sql.SQLException; import lucee.commons.io.log.Log; import lucee.commons.lang.ExceptionUtil; import lucee.runtime.PageContext; import lucee.runtime.PageContextImpl; import lucee.runtime.config.Config; import lucee.runtime.config.ConfigImpl; 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.Struct; import lucee.runtime.type.dt.DateTime; import lucee.runtime.type.dt.DateTimeImpl; 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; /** * 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)ThreadLocalPageContext.getConfig(pc); DatasourceConnectionPool pool = config.getDatasourceConnectionPool(); DatasourceConnection dc=pool.getDatasourceConnection(config,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 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,datasourceName,"",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 ["+datasourceName+"]"); return null; } String str=Caster.toString(query.get(KeyConstants._data)); if(str!=null && str.startsWith("struct:")) str=str.substring(7); if(mxStyle) return null; try{ 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; } catch(Exception e){ return null; } } @Override public void touchAfterRequest(PageContext pc) { setTimeSpan(pc); super.touchAfterRequest(pc); store(pc); } @Override public void store(PageContext pc) { DatasourceConnection dc = null; ConfigImpl ci = (ConfigImpl)ThreadLocalPageContext.getConfig(pc); DatasourceConnectionPool pool = ci.getDatasourceConnectionPool(); Log log=ci.getLog("scope"); try { pc = ThreadLocalPageContext.get(pc);// FUTURE change method interface DataSource ds; if(pc!=null) ds=pc.getDataSource(datasourceName); else ds=ci.getDataSource(datasourceName); dc=pool.getDatasourceConnection(null,ds,null,null); SQLExecutor executor=SQLExecutionFactory.getInstance(dc); executor.update(ci, cfid,appName, dc, getType(), sct,getTimeSpan(),log); } catch(Throwable t) { ExceptionUtil.rethrowIfNecessary(t); ScopeContext.error(log, t); } finally { if(dc!=null) pool.releaseDatasourceConnection(dc); } } @Override public void unstore(PageContext pc) { ConfigImpl ci=(ConfigImpl) ThreadLocalPageContext.getConfig(pc); DatasourceConnection dc = null; DatasourceConnectionPool pool = ci.getDatasourceConnectionPool(); Log log=ci.getLog("scope"); try { pc = ThreadLocalPageContext.get(pc);// FUTURE change method interface DataSource ds; if(pc!=null) ds=pc.getDataSource(datasourceName); else ds=ci.getDataSource(datasourceName); dc=pool.getDatasourceConnection(null,ds,null,null); SQLExecutor executor=SQLExecutionFactory.getInstance(dc); executor.delete(ci, cfid,appName, dc, getType(),log); } catch(Throwable t) { ExceptionUtil.rethrowIfNecessary(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; } }