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}