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.util.Date;
022
023import lucee.commons.io.log.Log;
024import lucee.commons.lang.ExceptionUtil;
025import lucee.commons.lang.StringUtil;
026import lucee.runtime.PageContext;
027import lucee.runtime.converter.ScriptConverter;
028import lucee.runtime.interpreter.CFMLExpressionInterpreter;
029import lucee.runtime.listener.ApplicationContext;
030import lucee.runtime.op.Caster;
031import lucee.runtime.type.KeyImpl;
032import lucee.runtime.type.Struct;
033import lucee.runtime.type.StructImpl;
034import lucee.runtime.type.dt.DateTime;
035import lucee.runtime.type.dt.DateTimeImpl;
036import lucee.runtime.type.dt.TimeSpan;
037import lucee.runtime.type.scope.Cookie;
038import lucee.runtime.type.scope.ScopeContext;
039import lucee.runtime.type.util.KeyConstants;
040
041/**
042 * client scope that store it's data in the cookie of the client
043 */
044public abstract class StorageScopeCookie extends StorageScopeImpl {
045
046        private static final long serialVersionUID = -3509170569488448183L;
047        
048        private static ScriptConverter serializer=new ScriptConverter();
049        protected static CFMLExpressionInterpreter evaluator=new CFMLExpressionInterpreter(false);
050        //private Cookie cookie;
051        private String cookieName;
052
053        //private TimeSpan timeout;
054        
055        
056        static {
057                ignoreSet.add(KeyConstants._cfid);
058                ignoreSet.add(KeyConstants._cftoken);
059                ignoreSet.add(KeyConstants._urltoken);
060                ignoreSet.add(KeyConstants._lastvisit);
061                ignoreSet.add(KeyConstants._hitcount);
062                ignoreSet.add(KeyConstants._timecreated);
063        }
064        
065
066        
067        /**
068         * Constructor of the class
069         * @param pc
070         * @param name
071         * @param sct
072         */
073        protected StorageScopeCookie(PageContext pc,String cookieName,String strType,int type,Struct sct) {
074                super(
075                                sct,
076                                doNowIfNull(pc,Caster.toDate(sct.get(TIMECREATED,null),false,pc.getTimeZone(),null)),
077                                doNowIfNull(pc,Caster.toDate(sct.get(LASTVISIT,null),false,pc.getTimeZone(),null)),
078                                -1,
079                                type==SCOPE_CLIENT?Caster.toIntValue(sct.get(HITCOUNT,"1"),1):0,
080                                strType,type);
081                this.cookieName=cookieName;     
082        }
083
084        /**
085         * Constructor of the class, clone existing
086         * @param other
087         */
088        protected StorageScopeCookie(StorageScopeCookie other,boolean deepCopy) {
089                super(other,deepCopy);
090                cookieName=other.cookieName;
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        public void touchAfterRequest(PageContext pc) {
099                boolean _isInit=isinit;
100                super.touchAfterRequest(pc);
101                if(!_isInit) return;
102                
103                ApplicationContext ac=pc.getApplicationContext();
104                TimeSpan timespan=(getType()==SCOPE_CLIENT)?ac.getClientTimeout():ac.getSessionTimeout();
105                Cookie cookie = pc.cookieScope();
106                
107                
108                Date exp = new DateTimeImpl(pc,System.currentTimeMillis()+timespan.getMillis(),true);
109                try {
110                        String ser=serializer.serializeStruct(sct, ignoreSet);
111                        if(hasChanges()){
112                                cookie.setCookie(KeyImpl.init(cookieName), ser,exp, false, "/", null);
113                        }
114                        cookie.setCookie(KeyImpl.init(cookieName+"_LV"), Caster.toString(_lastvisit.getTime()), exp, false, "/", null);
115                        
116                        if(getType()==SCOPE_CLIENT){
117                                cookie.setCookie(KeyImpl.init(cookieName+"_TC"), Caster.toString(timecreated.getTime()),exp, false, "/", null);
118                                cookie.setCookie(KeyImpl.init(cookieName+"_HC"), Caster.toString(sct.get(HITCOUNT,"")), exp, false, "/", null);
119                        }
120                        
121                } 
122                catch (Throwable t) {
123                        ExceptionUtil.rethrowIfNecessary(t);
124                }
125        }
126        
127        @Override
128        public String getStorageType() {
129                return "Cookie";
130        }
131
132
133        protected static Struct _loadData(PageContext pc, String cookieName, int type,String strType, Log log) {
134                String data = (String)pc.cookieScope().get(cookieName,null);
135                if(data!=null) {                        
136                        try {
137                                Struct sct = (Struct) evaluator.interpret(pc,data);
138                                long l;
139                                String str;
140                                
141                                // last visit
142                                str = (String)pc.cookieScope().get(cookieName+"_LV",null);
143                                if(!StringUtil.isEmpty(str)) {
144                                        l=Caster.toLongValue(str,0);
145                                        if(l>0)sct.setEL(LASTVISIT, new DateTimeImpl(pc,l,true));
146                                }
147                                
148                                
149                                if(type==SCOPE_CLIENT){
150                                        // hit count
151                                        str= (String)pc.cookieScope().get(cookieName+"_HC",null);
152                                                if(!StringUtil.isEmpty(str)) sct.setEL(HITCOUNT, Caster.toDouble(str,null));
153                                        
154                                        // time created
155                                        str = (String)pc.cookieScope().get(cookieName+"_TC",null);
156                                        if(!StringUtil.isEmpty(str)) {
157                                                l=Caster.toLongValue(str,0);
158                                                if(l>0)sct.setEL(TIMECREATED, new DateTimeImpl(pc,l,true));
159                                        }
160                                }
161                                                                
162                                ScopeContext.info(log,"load data from cookie for "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID());
163                                return sct;
164                        } 
165                        catch (Exception e) {
166                                
167                        }
168                }
169                ScopeContext.info(log,"create new "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID());
170                
171                return new StructImpl();
172        }
173        
174        protected static boolean has(PageContext pc, String cookieName, int type,String strType) {
175                // TODO better impl
176                String data = (String)pc.cookieScope().get(cookieName,null);
177                return data!=null;
178                
179        }
180}