001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * Copyright (c) 2016, Lucee Assosication Switzerland 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or (at your option) any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 018 * 019 **/ 020package lucee.runtime.type.scope.storage; 021 022import java.io.IOException; 023 024import lucee.commons.io.cache.Cache; 025import lucee.commons.io.log.Log; 026import lucee.runtime.PageContext; 027import lucee.runtime.cache.CacheConnection; 028import lucee.runtime.cache.CacheUtil; 029import lucee.runtime.config.Config; 030import lucee.runtime.exp.ApplicationException; 031import lucee.runtime.exp.PageException; 032import lucee.runtime.functions.cache.Util; 033import lucee.runtime.op.Caster; 034import lucee.runtime.type.Struct; 035import lucee.runtime.type.dt.DateTime; 036import lucee.runtime.type.dt.DateTimeImpl; 037import lucee.runtime.type.scope.ScopeContext; 038import lucee.runtime.type.util.StructUtil; 039 040/** 041 * client scope that store it's data in a datasource 042 */ 043public abstract class StorageScopeCache extends StorageScopeImpl { 044 045 private static final long serialVersionUID = 6234854552927320080L; 046 public static final long SAVE_EXPIRES_OFFSET = 60*60*1000; 047 048 private final String cacheName; 049 private final String appName; 050 private final String cfid; 051 052 private long lastModified; 053 054 /** 055 * Constructor of the class 056 * @param pc 057 * @param name 058 * @param sct 059 * @param b 060 */ 061 protected StorageScopeCache(PageContext pc,String cacheName, String appName,String strType,int type,Struct sct, long lastModified) { 062 // !!! do not store the pagecontext or config object, this object is Serializable !!! 063 super( 064 sct, 065 doNowIfNull(pc.getConfig(),Caster.toDate(sct.get(TIMECREATED,null),false,pc.getTimeZone(),null)), 066 doNowIfNull(pc.getConfig(),Caster.toDate(sct.get(LASTVISIT,null),false,pc.getTimeZone(),null)), 067 -1, 068 type==SCOPE_CLIENT?Caster.toIntValue(sct.get(HITCOUNT,"1"),1):1 069 ,strType,type); 070 071 //this.isNew=isNew; 072 this.appName=appName; 073 this.cacheName=cacheName; 074 this.cfid=pc.getCFID(); 075 this.lastModified=lastModified; 076 } 077 078 public long lastModified() { 079 return lastModified; 080 } 081 082 /** 083 * Constructor of the class, clone existing 084 * @param other 085 */ 086 protected StorageScopeCache(StorageScopeCache other,boolean deepCopy) { 087 super(other,deepCopy); 088 089 this.appName=other.appName; 090 this.cacheName=other.cacheName; 091 this.cfid=other.cfid; 092 this.lastModified=other.lastModified; 093 } 094 095 private static DateTime doNowIfNull(Config config,DateTime dt) { 096 if(dt==null)return new DateTimeImpl(config); 097 return dt; 098 } 099 100 @Override 101 public void touchAfterRequest(PageContext pc) { 102 setTimeSpan(pc); 103 super.touchAfterRequest(pc); 104 //if(super.hasContent()) 105 store(pc.getConfig()); 106 } 107 108 @Override 109 public String getStorageType() { 110 return "Cache"; 111 } 112 113 @Override 114 public void touchBeforeRequest(PageContext pc) { 115 setTimeSpan(pc); 116 super.touchBeforeRequest(pc); 117 } 118 119 protected static StorageValue _loadData(PageContext pc, String cacheName, String appName, String strType, Log log) throws PageException { 120 Cache cache = getCache(pc.getConfig(),cacheName); 121 String key=getKey(pc.getCFID(),appName,strType); 122 123 Object val = cache.getValue(key,null); 124 125 if(val instanceof StorageValue) { 126 ScopeContext.info(log,"load existing data from cache ["+cacheName+"] to create "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID()); 127 return (StorageValue)val; 128 } 129 ScopeContext.info(log,"create new "+strType+" scope for "+pc.getApplicationContext().getName()+"/"+pc.getCFID()+" in cache ["+cacheName+"]"); 130 return null; 131 } 132 133 public synchronized void store(Config config) { 134 try { 135 Cache cache = getCache(config, cacheName); 136 String key=getKey(cfid, appName, getTypeAsString()); 137 138 /* / merge existing data if necessary ; MARK disabled merge 139 Object existing = cache.getValue(key,null); 140 // cached data changed in meantime 141 if(existing instanceof StorageValue && ((StorageValue)existing).lastModified()>lastModified()) { 142 Struct trg=((StorageValue)existing).getValue(); 143 StructUtil.copy(sct, trg, true); 144 sct=trg; 145 }*/ 146 147 cache.put(key, new StorageValue(sct),null,new Long(getTimeSpan())); 148 } 149 catch (Exception pe) {pe.printStackTrace();} 150 } 151 152 153 public synchronized void unstore(Config config) { 154 try { 155 Cache cache = getCache(config, cacheName); 156 String key=getKey(cfid, appName, getTypeAsString()); 157 cache.remove(key); 158 } 159 catch (Exception pe) {} 160 } 161 162 163 private static Cache getCache(Config config, String cacheName) throws PageException { 164 try { 165 CacheConnection cc = Util.getCacheConnection(config,cacheName); 166 if(!cc.isStorage()) 167 throw new ApplicationException("storage usage for this cache is disabled, you can enable this in the lucee administrator."); 168 return CacheUtil.getInstance(cc,config); //cc.getInstance(config); 169 170 } catch (IOException e) { 171 throw Caster.toPageException(e); 172 } 173 } 174 175 176 public static String getKey(String cfid, String appName, String type) { 177 return new StringBuilder("lucee-storage:").append(type).append(":").append(cfid).append(":").append(appName).toString().toUpperCase(); 178 } 179}