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.cfml; 020import java.io.IOException; 021import java.util.Iterator; 022import java.util.Map; 023 024import lucee.commons.io.res.Resource; 025import lucee.commons.io.res.ResourceProvider; 026import lucee.commons.io.res.ResourceProviderPro; 027import lucee.commons.io.res.Resources; 028import lucee.commons.io.res.util.ResourceLockImpl; 029import lucee.commons.io.res.util.ResourceUtil; 030import lucee.commons.lang.ExceptionUtil; 031import lucee.commons.lang.StringUtil; 032import lucee.runtime.Component; 033import lucee.runtime.PageContext; 034import lucee.runtime.config.ConfigWebUtil; 035import lucee.runtime.engine.ThreadLocalPageContext; 036import lucee.runtime.exp.ApplicationException; 037import lucee.runtime.exp.PageException; 038import lucee.runtime.exp.PageRuntimeException; 039import lucee.runtime.op.Caster; 040import lucee.runtime.type.Array; 041 042public class CFMLResourceProvider implements ResourceProviderPro { 043 044 private static final Object[] ZERO_ARGS = new Object[0]; 045 046 private int lockTimeout=20000; 047 private final ResourceLockImpl lock=new ResourceLockImpl(lockTimeout,false); 048 private String scheme; 049 private Map args; 050 //private ResourceProvider provider; 051 private Resources resources; 052 053 private String cfcPath; 054 055 private Component component; 056 057 private boolean useStreams=false; 058 059 060 061 @Override 062 public ResourceProvider init(String scheme, Map args) { 063 this.scheme=scheme; 064 this.args=args; 065 066 // CFC Path 067 cfcPath=Caster.toString(args.get("cfc"),null); 068 if(StringUtil.isEmpty(cfcPath,true)) 069 cfcPath=Caster.toString(args.get("component"),null); 070 cfcPath=ConfigWebUtil.fixComponentPath(cfcPath); 071 072 // use Streams for data 073 Boolean _useStreams = Caster.toBoolean(args.get("use-streams"),null); 074 if(_useStreams==null)_useStreams = Caster.toBoolean(args.get("usestreams"),null); 075 076 if(_useStreams!=null)useStreams=_useStreams.booleanValue(); 077 078 return this; 079 } 080 081 @Override 082 public Resource getResource(String path) { 083 path=ResourceUtil.removeScheme(scheme,path); 084 path=ResourceUtil.prettifyPath(path); 085 if(!StringUtil.startsWith(path,'/'))path="/"+path; 086 return callResourceRTE(null, null, "getResource", new Object[]{path},false); 087 } 088 089 @Override 090 public String getScheme() { 091 return scheme; 092 } 093 094 @Override 095 public Map getArguments() { 096 return args; 097 } 098 099 @Override 100 public void setResources(Resources resources) { 101 this.resources=resources; 102 } 103 104 105 @Override 106 public boolean isCaseSensitive() { 107 return callbooleanRTE(null,null, "isCaseSensitive", ZERO_ARGS); 108 } 109 110 @Override 111 public boolean isModeSupported() { 112 return callbooleanRTE(null,null, "isModeSupported", ZERO_ARGS); 113 } 114 115 @Override 116 public boolean isAttributesSupported() { 117 return callbooleanRTE(null,null, "isAttributesSupported", ZERO_ARGS); 118 } 119 120 public int getLockTimeout() { 121 return lockTimeout; 122 } 123 124 125 126 @Override 127 public void lock(Resource res) throws IOException { 128 lock.lock(res); 129 } 130 131 @Override 132 public void unlock(Resource res) { 133 lock.unlock(res); 134 } 135 136 @Override 137 public void read(Resource res) throws IOException { 138 lock.read(res); 139 } 140 141 public boolean isUseStreams() { 142 return useStreams; 143 } 144 145 146 Resource callResourceRTE(PageContext pc,Component cfc,String methodName, Object[] args, boolean allowNull) { 147 pc = ThreadLocalPageContext.get(pc); 148 try { 149 Object res = call(pc,getCFC(pc,cfc), methodName, args); 150 if(allowNull && res==null) return null; 151 return new CFMLResource(this,Caster.toComponent(res)); 152 } 153 catch (PageException pe) {pe.printStackTrace(); 154 throw new PageRuntimeException(pe); 155 } 156 } 157 158 Resource[] callResourceArrayRTE(PageContext pc,Component cfc,String methodName, Object[] args) { 159 pc = ThreadLocalPageContext.get(pc); 160 try { 161 Array arr = Caster.toArray(call(pc,getCFC(pc,cfc), methodName, args)); 162 Iterator<Object> it = arr.valueIterator(); 163 CFMLResource[] resources=new CFMLResource[arr.size()]; 164 int index=0; 165 while(it.hasNext()){ 166 resources[index++]=new CFMLResource(this,Caster.toComponent(it.next())); 167 } 168 return resources; 169 } 170 catch (PageException pe) { 171 throw new PageRuntimeException(pe); 172 } 173 } 174 175 176 int callintRTE(PageContext pc,Component cfc,String methodName, Object[] args) { 177 try { 178 return callint(pc,cfc, methodName, args); 179 } 180 catch (PageException pe) { 181 throw new PageRuntimeException(pe); 182 } 183 } 184 int callint(PageContext pc,Component cfc,String methodName, Object[] args) throws PageException { 185 return Caster.toIntValue(call(pc,cfc,methodName, args)); 186 } 187 188 long calllongRTE(PageContext pc,Component cfc,String methodName, Object[] args) { 189 try { 190 return calllong(pc,cfc, methodName, args); 191 } 192 catch (PageException pe) { 193 throw new PageRuntimeException(pe); 194 } 195 } 196 long calllong(PageContext pc,Component cfc,String methodName, Object[] args) throws PageException { 197 return Caster.toLongValue(call(pc,cfc,methodName, args)); 198 } 199 200 boolean callbooleanRTE(PageContext pc,Component cfc,String methodName, Object[] args) { 201 try { 202 return callboolean(pc,cfc, methodName, args); 203 } 204 catch (PageException pe) { 205 throw new PageRuntimeException(pe); 206 } 207 } 208 boolean callboolean(PageContext pc,Component cfc,String methodName, Object[] args) throws PageException { 209 return Caster.toBooleanValue(call(pc,cfc,methodName, args)); 210 } 211 212 String callStringRTE(PageContext pc,Component cfc,String methodName, Object[] args) { 213 try { 214 return Caster.toString(call(pc,cfc,methodName, args)); 215 } 216 catch (PageException pe) { 217 throw new PageRuntimeException(pe); 218 } 219 } 220 221 String callString(PageContext pc,Component cfc,String methodName, Object[] args) throws PageException { 222 return Caster.toString(call(pc,cfc,methodName, args)); 223 } 224 225 Object callRTE(PageContext pc,Component cfc,String methodName, Object[] args) { 226 try { 227 return call(pc,cfc,methodName, args); 228 } 229 catch (PageException pe) { 230 throw new PageRuntimeException(pe); 231 } 232 } 233 234 Object call(PageContext pc,Component cfc,String methodName, Object[] args) throws PageException { 235 pc = ThreadLocalPageContext.get(pc); 236 return getCFC(pc, cfc).call(pc, methodName, args); 237 } 238 239 private Component getCFC(PageContext pc,Component cfc) throws PageException { 240 if(cfc!=null) return cfc; 241 242 if(component!=null) return component; 243 244 if(StringUtil.isEmpty(cfcPath,true))throw new ApplicationException("you need to define the argument [component] for the [CFMLResourceProvider]"); 245 cfcPath=cfcPath.trim(); 246 component=pc.loadComponent(cfcPath); 247 call(pc, component, "init", new Object[]{scheme,Caster.toStruct(args)}); 248 249 return component; 250 } 251 252 @Override 253 public char getSeparator() { 254 try { 255 String str=callStringRTE(null,component,"getSeparator",ZERO_ARGS); 256 if(StringUtil.length(str,true)==1) return str.charAt(0); 257 } 258 catch(Throwable t){ 259 ExceptionUtil.rethrowIfNecessary(t); 260 } 261 return '/'; 262 } 263 264}