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 lucee.commons.io.IOUtil; 022import lucee.commons.io.log.Log; 023import lucee.commons.io.res.Resource; 024import lucee.commons.io.res.util.ResourceUtil; 025import lucee.commons.lang.ExceptionUtil; 026import lucee.commons.lang.StringUtil; 027import lucee.runtime.PageContext; 028import lucee.runtime.config.Config; 029import lucee.runtime.config.ConfigImpl; 030import lucee.runtime.config.ConfigWeb; 031import lucee.runtime.converter.ScriptConverter; 032import lucee.runtime.interpreter.CFMLExpressionInterpreter; 033import lucee.runtime.op.Caster; 034import lucee.runtime.type.Struct; 035import lucee.runtime.type.StructImpl; 036import lucee.runtime.type.dt.DateTime; 037import lucee.runtime.type.dt.DateTimeImpl; 038import lucee.runtime.type.scope.ScopeContext; 039 040/** 041 * client scope that store it's data in a resource 042 */ 043public abstract class StorageScopeFile extends StorageScopeImpl { 044 045 private static final long serialVersionUID = -7519591903822909934L; 046 047 public static final String STORAGE_TYPE = "File"; 048 049 private static ScriptConverter serializer=new ScriptConverter(); 050 protected static CFMLExpressionInterpreter evaluator=new CFMLExpressionInterpreter(false); 051 052 private Resource res; 053 054 /** 055 * Constructor of the class 056 * @param pc 057 * @param name 058 * @param sct 059 */ 060 protected StorageScopeFile(PageContext pc,Resource res,String strType,int type,Struct sct) { 061 super( 062 sct==null?(sct=new StructImpl()):sct, 063 doNowIfNull(pc,Caster.toDate(sct.get(TIMECREATED,null),false,pc.getTimeZone(),null)), 064 doNowIfNull(pc,Caster.toDate(sct.get(LASTVISIT,null),false,pc.getTimeZone(),null)), 065 -1, 066 type==SCOPE_CLIENT?Caster.toIntValue(sct.get(HITCOUNT,"1"),1):0, 067 strType,type); 068 069 this.res =res;// pc.getConfig().getClientScopeDir().getRealResource(name+"-"+pc.getCFID()+".script"); 070 071 } 072 private static DateTime doNowIfNull(PageContext pc,DateTime dt) { 073 if(dt==null)return new DateTimeImpl(pc.getConfig()); 074 return dt; 075 } 076 077 /** 078 * Constructor of the class, clone existing 079 * @param other 080 */ 081 protected StorageScopeFile(StorageScopeFile other,boolean deepCopy) { 082 super(other,deepCopy); 083 this.res=other.res; 084 } 085 086 @Override 087 public void touchBeforeRequest(PageContext pc) { 088 setTimeSpan(pc); 089 super.touchBeforeRequest(pc); 090 } 091 092 @Override 093 public void touchAfterRequest(PageContext pc) { 094 setTimeSpan(pc); 095 super.touchAfterRequest(pc); 096 store(pc.getConfig()); 097 } 098 099 100 101 @Override 102 public void store(Config config) { 103 //if(!super.hasContent()) return; 104 try { 105 if(!res.exists())ResourceUtil.createFileEL(res, true); 106 IOUtil.write(res, (getTimeSpan()+System.currentTimeMillis())+":"+serializer.serializeStruct(sct, ignoreSet), "UTF-8", false); 107 } 108 catch (Throwable t) { 109 ExceptionUtil.rethrowIfNecessary(t); 110 } 111 } 112 113 protected static Struct _loadData(PageContext pc,Resource res, Log log) { 114 if(res.exists()) { 115 try { 116 String str=IOUtil.toString(res,"UTF-8"); 117 int index=str.indexOf(':'); 118 if(index!=-1){ 119 long expires=Caster.toLongValue(str.substring(0,index),-1L); 120 // check is for backward compatibility, old files have no expires date inside. they do ot expire 121 if(expires!=-1) { 122 str=str.substring(index+1); 123 /*if(checkExpires && expires<System.currentTimeMillis()){ 124 print.o("expired("+new Date(expires)+"):"+res); 125 return null; 126 } 127 else { 128 str=str.substring(index+1); 129 print.o("not expired("+new Date(expires)+"):"+res); 130 print.o(str); 131 }*/ 132 } 133 } 134 Struct s = (Struct) evaluator.interpret(pc,str); 135 ScopeContext.info(log,"load existing file storage ["+res+"]"); 136 return s; 137 } 138 catch (Throwable t) { 139 ExceptionUtil.rethrowIfNecessary(t); 140 ScopeContext.error(log, t); 141 } 142 } 143 ScopeContext.info(log,"create new file storage ["+res+"]"); 144 return null; 145 } 146 147 148 149 public void unstore(Config config) { 150 try { 151 if(!res.exists())return; 152 res.remove(true); 153 } 154 catch (Throwable t) { 155 ExceptionUtil.rethrowIfNecessary(t); 156 } 157 } 158 159 protected static Resource _loadResource(ConfigWeb config, int type,String name, String cfid) { 160 ConfigImpl ci = (ConfigImpl)config; 161 Resource dir= type==SCOPE_CLIENT?ci.getClientScopeDir():ci.getSessionScopeDir(); 162 return dir.getRealResource(getFolderName(name,cfid,true)); 163 } 164 165 166 167 /** 168 * return a folder name that match given input 169 * @param name 170 * @param cfid 171 * @param addExtension 172 * @return 173 */ 174 public static String getFolderName(String name, String cfid,boolean addExtension) { 175 if(addExtension) return getFolderName(name, cfid, false)+".scpt"; 176 if(!StringUtil.isEmpty(name)) 177 name=encode(name);//StringUtil.toVariableName(StringUtil.toLowerCase(name)); 178 else 179 name="__empty__"; 180 return name+"/"+cfid.substring(0,2)+"/"+cfid.substring(2); 181 } 182 183 184 @Override 185 public String getStorageType() { 186 return STORAGE_TYPE; 187 } 188 189 190}