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.commons.io.res.type.cache; 020 021import java.io.IOException; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027 028import lucee.commons.io.cache.Cache; 029import lucee.commons.io.cache.CacheEntry; 030import lucee.commons.io.res.Resource; 031import lucee.commons.io.res.ResourceProvider; 032import lucee.commons.io.res.ResourceProviderPro; 033import lucee.commons.io.res.Resources; 034import lucee.commons.io.res.util.ResourceLockImpl; 035import lucee.commons.io.res.util.ResourceUtil; 036import lucee.commons.lang.StringUtil; 037import lucee.runtime.PageContext; 038import lucee.runtime.cache.ram.RamCache; 039import lucee.runtime.config.ConfigImpl; 040import lucee.runtime.engine.ThreadLocalPageContext; 041import lucee.runtime.functions.cache.Util; 042import lucee.runtime.op.Caster; 043import lucee.runtime.op.Constants; 044import lucee.runtime.type.Struct; 045 046 047/** 048 * Resource Provider for ram resource 049 */ 050public final class CacheResourceProvider implements ResourceProviderPro { 051 052 private String scheme="ram"; 053 054 boolean caseSensitive=true; 055 private long lockTimeout=1000; 056 private ResourceLockImpl lock=new ResourceLockImpl(lockTimeout,caseSensitive); 057 private Map arguments; 058 059 private Cache defaultCache; 060 061 private Set<Integer> inits=new HashSet<Integer>(); 062 063 //private Config config; 064 065 066 /** 067 * initalize ram resource 068 * @param scheme 069 * @param arguments 070 * @return RamResource 071 */ 072 public ResourceProvider init(String scheme,Map arguments) { 073 if(!StringUtil.isEmpty(scheme))this.scheme=scheme; 074 075 if(arguments!=null) { 076 this.arguments=arguments; 077 Object oCaseSensitive= arguments.get("case-sensitive"); 078 if(oCaseSensitive!=null) { 079 caseSensitive=Caster.toBooleanValue(oCaseSensitive,true); 080 } 081 082 // lock-timeout 083 Object oTimeout = arguments.get("lock-timeout"); 084 if(oTimeout!=null) { 085 lockTimeout=Caster.toLongValue(oTimeout,lockTimeout); 086 } 087 } 088 lock.setLockTimeout(lockTimeout); 089 lock.setCaseSensitive(caseSensitive); 090 091 092 093 return this; 094 } 095 096 097 098 @Override 099 public Resource getResource(String path) { 100 path=ResourceUtil.removeScheme(scheme,path); 101 if(!StringUtil.startsWith(path,'/'))path="/"+path; 102 return new CacheResource(this,path); 103 } 104 105 /** 106 * returns core for this path if exists, otherwise return null 107 * @param path 108 * @return core or null 109 */ 110 CacheResourceCore getCore(String path,String name) { 111 Object obj = getCache().getValue(toKey(path,name),null); 112 if(obj instanceof CacheResourceCore) return (CacheResourceCore) obj; 113 return null; 114 } 115 116 void touch(String path,String name) { 117 Cache cache = getCache(); 118 CacheEntry ce = cache.getCacheEntry(toKey(path,name),null); 119 if(ce!=null){ 120 cache.put(ce.getKey(), ce.getValue(), ce.idleTimeSpan(), ce.liveTimeSpan()); 121 } 122 } 123 124 125 Struct getMeta(String path,String name) { 126 CacheEntry ce = getCache().getCacheEntry(toKey(path,name),null); 127 if(ce!=null) return ce.getCustomInfo(); 128 return null; 129 } 130 131 String[] getChildNames(String path) throws IOException { 132 List<Object> list = getCache().values(new ChildrenFilter(path)); 133 String[] arr = new String[list.size()]; 134 Iterator<Object> it = list.iterator(); 135 int index=0; 136 while(it.hasNext()){ 137 arr[index++]=((CacheResourceCore) it.next()).getName(); 138 } 139 // TODO remove none CacheResourceCore elements 140 return arr; 141 } 142 /*CacheResourceCore[] getChildren(String path) { 143 List list = getCache().values(new ChildrenFilter(path)); 144 CacheResourceCore[] arr = new CacheResourceCore[list.size()]; 145 Iterator it = list.iterator(); 146 int index=0; 147 while(it.hasNext()){ 148 arr[index++]=(CacheResourceCore) it.next(); 149 } 150 // TODO remove none CacheResourceCore elements 151 return arr; 152 }*/ 153 154 155 156 157 /** 158 * create a new core 159 * @param path 160 * @param type 161 * @return created core 162 * @throws IOException 163 */ 164 CacheResourceCore createCore(String path, String name, int type) throws IOException { 165 CacheResourceCore value = new CacheResourceCore(type,path,name); 166 getCache().put(toKey(path,name),value,null,null); 167 return value; 168 } 169 170 171 172 173 174 175 176 void removeCore(String path, String name) throws IOException { 177 getCache().remove(toKey(path,name)); 178 } 179 180 181 @Override 182 public String getScheme() { 183 return scheme; 184 } 185 @Override 186 public void setResources(Resources resources) { 187 //this.resources=resources; 188 } 189 190 @Override 191 public void lock(Resource res) throws IOException { 192 lock.lock(res); 193 } 194 195 @Override 196 public void unlock(Resource res) { 197 lock.unlock(res); 198 } 199 200 @Override 201 public void read(Resource res) throws IOException { 202 lock.read(res); 203 } 204 205 @Override 206 public boolean isAttributesSupported() { 207 return true; 208 } 209 210 @Override 211 public boolean isCaseSensitive() { 212 return caseSensitive; 213 } 214 215 @Override 216 public boolean isModeSupported() { 217 return true; 218 } 219 220 @Override 221 public Map getArguments() { 222 return arguments; 223 } 224 225 226 public Cache getCache() { 227 228 PageContext pc = ThreadLocalPageContext.get(); 229 Cache c = Util.getDefault(pc,ConfigImpl.CACHE_DEFAULT_RESOURCE,null); 230 if(c==null) { 231 if(defaultCache==null)defaultCache=new RamCache().init(0, 0, RamCache.DEFAULT_CONTROL_INTERVAL); 232 c=defaultCache; 233 } 234 235 if(!inits.contains(c.hashCode())){ 236 String k = toKey("null",""); 237 if(!c.contains(k)) { 238 CacheResourceCore value = new CacheResourceCore(CacheResourceCore.TYPE_DIRECTORY,null,""); 239 c.put(k,value,Constants.LONG_ZERO,Constants.LONG_ZERO); 240 } 241 inits.add(c.hashCode()); 242 } 243 return c; 244 } 245 246 247 248 private String toKey(String path, String name) { 249 if(caseSensitive) return path+":"+name; 250 return (path+":"+name).toLowerCase(); 251 } 252 253 @Override 254 public char getSeparator() { 255 return '/'; 256 } 257 258 259}