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}