/**
* Copyright (c) 2015, Lucee Assosication Switzerland. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.runtime.cache.tag;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import lucee.commons.digest.HashUtil;
import lucee.commons.io.cache.Cache;
import lucee.commons.io.cache.CacheEntry;
import lucee.commons.io.res.Resource;
import lucee.commons.lang.KeyGenerator;
import lucee.runtime.PageContext;
import lucee.runtime.PageSource;
import lucee.runtime.cache.CacheUtil;
import lucee.runtime.cache.tag.query.QueryCacheItem;
import lucee.runtime.cache.tag.udf.UDFArgConverter;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.config.ConfigWeb;
import lucee.runtime.config.ConfigWebImpl;
import lucee.runtime.db.SQL;
import lucee.runtime.exp.PageException;
import lucee.runtime.net.proxy.ProxyData;
import lucee.runtime.op.Caster;
import lucee.runtime.tag.HttpParamBean;
import lucee.runtime.type.Struct;
import lucee.runtime.type.UDF;
import lucee.runtime.type.util.KeyConstants;
public class CacheHandlerCollectionImpl implements CacheHandlerCollection {
public static final char CACHE_DEL = ';';
public static final char CACHE_DEL2 = ':';
private ConfigWeb cw;
Map<String,CacheHandler> handlers=new HashMap<String, CacheHandler>();
//private final CacheHandler rch;
//private final CacheHandler sch;
//private final CacheHandler tch;
/**
*
* @param cw config object this Factory is related
* @param cacheType type of the cache, see Config.CACHE_TYPE_XXX
*/
protected CacheHandlerCollectionImpl(ConfigWeb cw, int cacheType) {
this.cw=cw;
Iterator<Entry<String, Class<CacheHandler>>> it = ((ConfigWebImpl)cw).getCacheHandlers();
Entry<String, Class<CacheHandler>> e;
CacheHandler ch;
while(it.hasNext()) {
e = it.next();
try {
ch=e.getValue().newInstance();
ch.init(cw,e.getKey(),cacheType);
handlers.put(e.getKey(), ch);
} catch (Exception ex) {}
}
}
@Override
public CacheHandler getInstanceMatchingObject(Object cachedWithin, CacheHandler defaultValue){
Iterator<CacheHandler> it = handlers.values().iterator();
CacheHandler ch;
while(it.hasNext()){
ch = it.next();
if(ch.acceptCachedWithin(cachedWithin)) return ch;
}
return defaultValue;
}
@Override
public CacheHandler getInstance(String cacheHandlerId, CacheHandler defaultValue){
// return cache handler matching
CacheHandler ch = handlers.get(cacheHandlerId);
if(ch!=null) return ch;
ch = handlers.get(cacheHandlerId.toLowerCase().trim());
if(ch!=null) return ch;
return defaultValue;
}
@Override
public int size(PageContext pc) throws PageException {
int size=0;
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
size+=it.next().size(pc);
}
return size;
}
@Override
public void clear(PageContext pc) throws PageException {
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
it.next().clear(pc);
}
}
@Override
public void clear(PageContext pc, CacheHandlerFilter filter) throws PageException {
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
it.next().clear(pc,filter);
}
}
@Override
public void clean(PageContext pc) throws PageException {
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
it.next().clean(pc);
}
}
@Override
public void remove(PageContext pc, String id) throws PageException {
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
it.next().remove(pc,id);
}
}
@Override
public List<String> getPatterns() {
List<String> patterns=new ArrayList<String>();
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
patterns.add(it.next().pattern());
}
return patterns;
}
public static String createId(PageSource[] sources) throws PageException{
String str;
if(sources.length==1) {
str= sources[0].getDisplayPath();
}
else {
StringBuilder sb=new StringBuilder();
for(int i=0;i<sources.length;i++){
if(i>0)sb.append(";");
sb.append(sources[i].getDisplayPath());
}
str=sb.toString();
}
try {
return CacheUtil.key(KeyGenerator.createKey(str));
}
catch (IOException e) {
throw Caster.toPageException(e);
}
}
public static String createId(SQL sql, String datasource, String username,String password, int returnType) throws PageException{
try {
return CacheUtil.key(KeyGenerator.createKey(sql.toHashString()+datasource+username+password+returnType));
}
catch (IOException e) {
throw Caster.toPageException(e);
}
}
public static String createId(Resource res, boolean binary) {
StringBuilder sb=new StringBuilder()
.append(res.getAbsolutePath())
.append(CACHE_DEL)
.append(binary)
.append(CACHE_DEL);
return HashUtil.create64BitHashAsString(sb, Character.MAX_RADIX);
}
public static String createId(String wsdlUrl, String username,String password, ProxyData proxyData, String methodName,Object[] arguments, Struct namedArguments) {
StringBuilder sb=new StringBuilder()
.append(wsdlUrl)
.append(CACHE_DEL)
.append(username)
.append(CACHE_DEL)
.append(password)
.append(CACHE_DEL)
.append(proxyData)
.append(CACHE_DEL)
.append(methodName);
createIdArgs(sb,arguments,namedArguments);
return HashUtil.create64BitHashAsString(sb, Character.MAX_RADIX);
}
public static String createId(UDF udf, Object[] args, Struct values) {
String src = udf.getSource();
StringBuilder sb=new StringBuilder()
.append(HashUtil.create64BitHash(src==null?"":src))
.append(CACHE_DEL)
.append(HashUtil.create64BitHash(udf.getFunctionName()))
.append(CACHE_DEL);
createIdArgs(sb,args,values);
return HashUtil.create64BitHashAsString(sb, Character.MAX_RADIX);
}
private static void createIdArgs(StringBuilder sb, Object[] args, Struct namedArgs) {
if(namedArgs!=null) {
// argumentCollection
Struct sct;
if(namedArgs.size()==1 && (sct=Caster.toStruct(namedArgs.get(KeyConstants._argumentCollection,null),null))!=null) {
sb.append(_createId(sct));
}
else sb.append(_createId(namedArgs));
}
else if(args!=null){
sb.append(_createId(args));
}
}
private static String _createId(Object values) {
return HashUtil.create64BitHash(UDFArgConverter.serialize(values))+"";
}
public static String createId(String url, String urlToken, short method,
ArrayList<HttpParamBean> params, String username, String password,
int port, String proxyserver, int proxyport, String proxyuser,
String proxypassword, String useragent) {
StringBuilder sb=new StringBuilder()
.append(url)
.append(CACHE_DEL)
.append(urlToken)
.append(CACHE_DEL)
.append(method)
.append(CACHE_DEL)
.append(username)
.append(CACHE_DEL)
.append(password)
.append(CACHE_DEL)
.append(port)
.append(CACHE_DEL)
.append(proxyserver)
.append(CACHE_DEL)
.append(proxyport)
.append(CACHE_DEL)
.append(proxyuser)
.append(CACHE_DEL)
.append(proxypassword)
.append(CACHE_DEL)
.append(proxypassword)
.append(CACHE_DEL)
.append(useragent)
.append(CACHE_DEL);
HttpParamBean hpb;
Iterator<HttpParamBean> it = params.iterator();
while(it.hasNext()){
hpb=it.next();
sb.append(hpb.getEncoded())
.append(CACHE_DEL)
.append(hpb.getMimeType())
.append(CACHE_DEL)
.append(hpb.getName())
.append(CACHE_DEL)
.append(hpb.getType())
.append(CACHE_DEL)
.append(toString(hpb.getValue()))
.append(CACHE_DEL)
.append(toString(hpb.getFile()))
.append(CACHE_DEL);
}
return HashUtil.create64BitHashAsString(sb.toString());
}
private static Object toString(Object value) {
return Caster.toString(value,null);
}
private static Object toString(Resource file) {
return file==null?"":file.getAbsolutePath();
}
public static String toStringCacheName(int type, String defaultValue) {
switch(type){
case ConfigImpl.CACHE_TYPE_FUNCTION: return "function";
case ConfigImpl.CACHE_TYPE_INCLUDE: return "include";
case ConfigImpl.CACHE_TYPE_OBJECT: return "object";
case ConfigImpl.CACHE_TYPE_QUERY: return "query";
case ConfigImpl.CACHE_TYPE_RESOURCE: return "resource";
case ConfigImpl.CACHE_TYPE_TEMPLATE: return "template";
case ConfigImpl.CACHE_TYPE_HTTP: return "http";
case ConfigImpl.CACHE_TYPE_FILE: return "file";
case ConfigImpl.CACHE_TYPE_WEBSERVICE: return "webservice";
}
return defaultValue;
}
public static CacheItem toCacheItem(Object value, CacheItem defaultValue) {
if(value instanceof CacheItem) return (CacheItem) value;
return defaultValue;
}
@Override
public void release(PageContext pc) throws PageException {
Iterator<CacheHandler> it = handlers.values().iterator();
while(it.hasNext()){
it.next().release(pc);
}
}
public static void clear(PageContext pc, Cache cache, CacheHandlerFilter filter) {
try{
Iterator<CacheEntry> it = cache.entries().iterator();
CacheEntry ce;
Object obj;
while(it.hasNext()){
ce = it.next();
if(filter==null) {
cache.remove(ce.getKey());
continue;
}
obj=ce.getValue();
if(obj instanceof QueryCacheItem)
obj=((QueryCacheItem)obj).getQuery();
if(filter.accept(obj))
cache.remove(ce.getKey());
}
}
catch (IOException e) {}
}
}