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}