001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.type.scope.storage; 020 021import java.sql.SQLException; 022 023import lucee.commons.io.log.Log; 024import lucee.commons.lang.ExceptionUtil; 025import lucee.runtime.PageContext; 026import lucee.runtime.PageContextImpl; 027import lucee.runtime.config.Config; 028import lucee.runtime.config.ConfigImpl; 029import lucee.runtime.db.DataSource; 030import lucee.runtime.db.DatasourceConnection; 031import lucee.runtime.db.DatasourceConnectionPool; 032import lucee.runtime.debug.DebuggerPro; 033import lucee.runtime.debug.DebuggerUtil; 034import lucee.runtime.engine.ThreadLocalPageContext; 035import lucee.runtime.exp.ApplicationException; 036import lucee.runtime.exp.PageException; 037import lucee.runtime.op.Caster; 038import lucee.runtime.type.Query; 039import lucee.runtime.type.Struct; 040import lucee.runtime.type.dt.DateTime; 041import lucee.runtime.type.dt.DateTimeImpl; 042import lucee.runtime.type.scope.ScopeContext; 043import lucee.runtime.type.scope.storage.db.SQLExecutionFactory; 044import lucee.runtime.type.scope.storage.db.SQLExecutor; 045import lucee.runtime.type.util.KeyConstants; 046 047/** 048 * client scope that store it's data in a datasource 049 */ 050public abstract class StorageScopeDatasource extends StorageScopeImpl { 051 052 private static final long serialVersionUID = 239179599401918216L; 053 054 public static final String PREFIX = "cf"; 055 056 private String datasourceName; 057 058 private String appName; 059 060 private String cfid; 061 062 063 /** 064 * Constructor of the class 065 * @param pc 066 * @param name 067 * @param sct 068 * @param b 069 */ 070 protected StorageScopeDatasource(PageContext pc,String datasourceName, String strType,int type,Struct sct) { 071 super( 072 sct, 073 doNowIfNull(pc,Caster.toDate(sct.get(TIMECREATED,null),false,pc.getTimeZone(),null)), 074 doNowIfNull(pc,Caster.toDate(sct.get(LASTVISIT,null),false,pc.getTimeZone(),null)), 075 -1, 076 type==SCOPE_CLIENT?Caster.toIntValue(sct.get(HITCOUNT,"1"),1):0, 077 strType,type); 078 079 this.datasourceName=datasourceName; 080 appName=pc.getApplicationContext().getName(); 081 cfid=pc.getCFID(); 082 } 083 084 /** 085 * Constructor of the class, clone existing 086 * @param other 087 */ 088 protected StorageScopeDatasource(StorageScopeDatasource other,boolean deepCopy) { 089 super(other,deepCopy); 090 this.datasourceName=other.datasourceName; 091 } 092 093 private static DateTime doNowIfNull(PageContext pc,DateTime dt) { 094 if(dt==null)return new DateTimeImpl(pc.getConfig()); 095 return dt; 096 } 097 098 099 100 101 protected static Struct _loadData(PageContext pc, String datasourceName,String strType,int type, Log log, boolean mxStyle) throws PageException { 102 ConfigImpl config = (ConfigImpl)pc.getConfig(); 103 DatasourceConnectionPool pool = config.getDatasourceConnectionPool(); 104 DatasourceConnection dc=pool.getDatasourceConnection(((PageContextImpl)pc).getDataSource(datasourceName),null,null); 105 SQLExecutor executor=SQLExecutionFactory.getInstance(dc); 106 107 108 Query query; 109 110 try { 111 if(!dc.getDatasource().isStorage()) 112 throw new ApplicationException("storage usage for this datasource is disabled, you can enable this in the lucee administrator."); 113 query = executor.select(pc.getConfig(),pc.getCFID(),pc.getApplicationContext().getName(), dc, type,log, true); 114 } 115 catch (SQLException se) { 116 throw Caster.toPageException(se); 117 } 118 finally { 119 if(dc!=null) pool.releaseDatasourceConnection(config,dc,true); 120 } 121 122 if(query!=null && pc.getConfig().debug()) { 123 boolean debugUsage=DebuggerUtil.debugQueryUsage(pc,query); 124 ((DebuggerPro)pc.getDebugger()).addQuery(debugUsage?query:null,datasourceName,"",query.getSql(),query.getRecordcount(),((PageContextImpl)pc).getCurrentPageSource(null),query.getExecutionTime()); 125 } 126 boolean _isNew = query.getRecordcount()==0; 127 128 if(_isNew) { 129 ScopeContext.info(log,"create new "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID()+" in datasource ["+datasourceName+"]"); 130 return null; 131 } 132 String str=Caster.toString(query.get(KeyConstants._data)); 133 if(mxStyle) return null; 134 Struct s = (Struct)pc.evaluate(str); 135 ScopeContext.info(log,"load existing data from ["+datasourceName+"."+PREFIX+"_"+strType+"_data] to create "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID()); 136 137 return s; 138 } 139 140 @Override 141 public void touchAfterRequest(PageContext pc) { 142 setTimeSpan(pc); 143 super.touchAfterRequest(pc); 144 145 store(pc.getConfig()); 146 } 147 148 public void store(Config config) { 149 DatasourceConnection dc = null; 150 ConfigImpl ci = (ConfigImpl)config; 151 DatasourceConnectionPool pool = ci.getDatasourceConnectionPool(); 152 Log log=((ConfigImpl)config).getLog("scope"); 153 try { 154 PageContext pc = ThreadLocalPageContext.get();// FUTURE change method interface 155 DataSource ds; 156 if(pc!=null) ds=((PageContextImpl)pc).getDataSource(datasourceName); 157 else ds=config.getDataSource(datasourceName); 158 dc=pool.getDatasourceConnection(ds,null,null); 159 SQLExecutor executor=SQLExecutionFactory.getInstance(dc); 160 executor.update(config, cfid,appName, dc, getType(), sct,getTimeSpan(),log); 161 } 162 catch (Throwable t) { 163 ExceptionUtil.rethrowIfNecessary(t); 164 ScopeContext.error(log, t); 165 } 166 finally { 167 if(dc!=null) pool.releaseDatasourceConnection(config,dc,true); 168 } 169 } 170 171 public void unstore(Config config) { 172 ConfigImpl ci=(ConfigImpl) config; 173 DatasourceConnection dc = null; 174 175 176 DatasourceConnectionPool pool = ci.getDatasourceConnectionPool(); 177 Log log=((ConfigImpl)config).getLog("scope"); 178 try { 179 PageContext pc = ThreadLocalPageContext.get();// FUTURE change method interface 180 DataSource ds; 181 if(pc!=null) ds=((PageContextImpl)pc).getDataSource(datasourceName); 182 else ds=config.getDataSource(datasourceName); 183 dc=pool.getDatasourceConnection(ds,null,null); 184 SQLExecutor executor=SQLExecutionFactory.getInstance(dc); 185 executor.delete(config, cfid,appName, dc, getType(),log); 186 } 187 catch (Throwable t) { 188 ExceptionUtil.rethrowIfNecessary(t); 189 ScopeContext.error(log, t); 190 } 191 finally { 192 if(dc!=null) pool.releaseDatasourceConnection(ci,dc,true); 193 } 194 } 195 196 197 198 199 200 201 202 203 204 205 @Override 206 public void touchBeforeRequest(PageContext pc) { 207 setTimeSpan(pc); 208 super.touchBeforeRequest(pc); 209 } 210 211 @Override 212 public String getStorageType() { 213 return "Datasource"; 214 } 215 216 /** 217 * @return the datasourceName 218 */ 219 public String getDatasourceName() { 220 return datasourceName; 221 } 222}