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.cache.tag;
020
021import java.io.IOException;
022import java.util.HashMap;
023import java.util.Map;
024
025import lucee.commons.digest.HashUtil;
026import lucee.commons.lang.KeyGenerator;
027import lucee.runtime.PageContext;
028import lucee.runtime.PageSource;
029import lucee.runtime.cache.tag.request.RequestCacheHandler;
030import lucee.runtime.cache.tag.timespan.TimespanCacheHandler;
031import lucee.runtime.cache.tag.udf.UDFArgConverter;
032import lucee.runtime.config.Config;
033import lucee.runtime.config.ConfigImpl;
034import lucee.runtime.db.SQL;
035import lucee.runtime.exp.PageException;
036import lucee.runtime.functions.cache.Util;
037import lucee.runtime.op.Caster;
038import lucee.runtime.type.Struct;
039import lucee.runtime.type.UDF;
040import lucee.runtime.type.util.KeyConstants;
041
042public class CacheHandlerFactory { 
043
044        public static final int TYPE_TIMESPAN=1;
045        public static final int TYPE_REQUEST=2;
046        
047        public static final char CACHE_DEL = ';';
048        public static final char CACHE_DEL2 = ':';
049
050        
051        final RequestCacheHandler rch;
052        private Map<Config,TimespanCacheHandler> tschs=new HashMap<Config, TimespanCacheHandler>();
053        private int cacheDefaultType;
054        
055        protected CacheHandlerFactory(int cacheDefaultType) {
056                this.cacheDefaultType=cacheDefaultType;
057                rch=new RequestCacheHandler(cacheDefaultType);
058        }
059        
060        /**
061         * based on the cachedWithin Object we  choose the right Cachehandler and return it
062         * @return 
063         */
064        public CacheHandler getInstance(Config config,Object cachedWithin){
065                if(Caster.toTimespan(cachedWithin,null)!=null) {
066                        return getTimespanCacheHandler(config);
067                }
068                String str=Caster.toString(cachedWithin,"").trim();
069                if("request".equalsIgnoreCase(str)) return rch;
070                
071                return null;
072        }
073        
074        public CacheHandler getInstance(Config config,int type){
075                if(TYPE_TIMESPAN==type)return getTimespanCacheHandler(config);
076                if(TYPE_REQUEST==type) return rch;
077                return null;
078        }
079        
080        private CacheHandler getTimespanCacheHandler(Config config) {
081                TimespanCacheHandler tsch = tschs.get(config);
082                if(tsch==null) {
083                        tschs.put(config, tsch=new TimespanCacheHandler(cacheDefaultType, null));
084                }
085                return tsch;
086        }
087
088        public int size(PageContext pc) throws PageException {
089                int size=rch.size(pc);
090                size+=getTimespanCacheHandler(pc.getConfig()).size(pc);
091                return size;
092        }
093
094
095        public void clear(PageContext pc) throws PageException {
096                rch.clear(pc);
097                getTimespanCacheHandler(pc.getConfig()).clear(pc);
098        }
099        
100        public void clear(PageContext pc, CacheHandlerFilter filter) throws PageException {
101                rch.clear(pc,filter);
102                getTimespanCacheHandler(pc.getConfig()).clear(pc,filter);
103        }
104        
105        public void clean(PageContext pc) throws PageException {
106                rch.clean(pc);
107                getTimespanCacheHandler(pc.getConfig()).clean(pc);
108        }
109
110        public static String createId(PageSource[] sources) throws PageException{
111                String str;
112                if(sources.length==1) {
113                        str= sources[0].getDisplayPath();
114                }
115                else {
116                        StringBuilder sb=new StringBuilder();
117                        for(int i=0;i<sources.length;i++){
118                                if(i>0)sb.append(";");
119                                sb.append(sources[i].getDisplayPath());
120                        }
121                        str=sb.toString();
122                }
123                try {
124                        return Util.key(KeyGenerator.createKey(str));
125                }
126                catch (IOException e) {
127                        throw Caster.toPageException(e);
128                }
129        }
130
131        public static String createId(SQL sql, String datasource, String username,String password) throws PageException{
132                try {
133                        return Util.key(KeyGenerator.createKey(sql.toHashString()+datasource+username+password));
134                }
135                catch (IOException e) {
136                        throw Caster.toPageException(e);
137                }
138        }
139
140        public static String createId(UDF udf, Object[] args, Struct values) {
141                StringBuilder sb=new StringBuilder()
142                        .append(HashUtil.create64BitHash(udf.getPageSource().getDisplayPath()))
143                        .append(CACHE_DEL)
144                        .append(HashUtil.create64BitHash(udf.getFunctionName()))
145                        .append(CACHE_DEL);
146                
147                
148                
149                if(values!=null) {
150                        // argumentCollection
151                        Struct sct;
152                        if(values.size()==1 && (sct=Caster.toStruct(values.get(KeyConstants._argumentCollection,null),null))!=null) {
153                                sb.append(_createId(sct));
154                        }
155                        else sb.append(_createId(values));
156                }
157                else if(args!=null){
158                        sb.append(_createId(args));
159                }
160                return HashUtil.create64BitHashAsString(sb, Character.MAX_RADIX);
161        }
162
163        private static String _createId(Object values) {
164                return HashUtil.create64BitHash(UDFArgConverter.serialize(values))+"";
165        }
166        
167
168        public static String toStringType(int type, String defaultValue) {
169                switch(type){
170                case TYPE_REQUEST:      return "request";
171                case TYPE_TIMESPAN:     return "timespan";
172                }
173                return defaultValue;
174        }
175        
176        public static String toStringCacheName(int type, String defaultValue) {
177                switch(type){
178                case ConfigImpl.CACHE_DEFAULT_FUNCTION: return "function";
179                case ConfigImpl.CACHE_DEFAULT_INCLUDE:  return "include";
180                case ConfigImpl.CACHE_DEFAULT_OBJECT:   return "object";
181                case ConfigImpl.CACHE_DEFAULT_QUERY:    return "query";
182                case ConfigImpl.CACHE_DEFAULT_RESOURCE:         return "resource";
183                case ConfigImpl.CACHE_DEFAULT_TEMPLATE:         return "template";
184                }
185                return defaultValue;
186        }
187
188        public static CacheItem toCacheItem(Object value, CacheItem defaultValue) {
189                if(value instanceof CacheItem) return (CacheItem) value;
190                return defaultValue;
191        }
192}