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 coldfusion.cfc;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.OutputStream;
024import java.io.Serializable;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.Map;
028import java.util.Map.Entry;
029
030import javax.servlet.http.HttpServletRequest;
031import javax.servlet.http.HttpServletResponse;
032
033import lucee.loader.engine.CFMLEngine;
034import lucee.loader.engine.CFMLEngineFactory;
035import lucee.runtime.Component;
036import lucee.runtime.PageContext;
037import lucee.runtime.exp.PageException;
038import lucee.runtime.type.Collection.Key;
039import lucee.runtime.type.Struct;
040import lucee.runtime.util.Cast;
041import lucee.runtime.util.Creation;
042
043
044public class CFCProxy {
045        
046        private CFMLEngine engine;
047        private Cast caster;
048        private Creation creator;
049        
050        private Component cfc=null;
051    private String path;
052        private Map thisData;
053        private boolean invokeDirectly=true;
054        private boolean autoFlush;
055
056        public CFCProxy(String path) throws Throwable {
057                this(path, null, true);
058    }
059
060    public CFCProxy(String path, boolean invokeDirectly) throws Throwable {
061                this(path, null, invokeDirectly);
062    }
063
064    public CFCProxy(String path, Map initialThis) throws Throwable {
065        this(path, initialThis, true);
066    }
067
068    public CFCProxy(String path, Map initialThis, boolean invokeDirectly) throws Throwable {
069        engine = CFMLEngineFactory.getInstance();
070        caster = engine.getCastUtil();
071        creator = engine.getCreationUtil();
072        
073        this.path=path;
074                this.invokeDirectly=invokeDirectly;
075                setThisScope(initialThis);
076    }
077
078    private void initCFC(PageContext pc) {
079        if(cfc==null && (invokeDirectly || pc!=null)) {
080                        try {
081                                if(pc==null)pc=engine.getThreadPageContext();
082                                cfc=engine.getCreationUtil().createComponentFromPath(pc, path);
083                        } catch (PageException pe) {}
084        }
085        }
086        
087    public void setThisScope(Map data) {
088                if(data!=null) {
089                        if(thisData==null)this.thisData=new HashMap();
090                        
091                        Iterator<Entry> it = data.entrySet().iterator();
092                Entry entry;
093                while(it.hasNext()){
094                        entry = it.next();
095                        thisData.put(entry.getKey(), entry.getValue());
096                }
097                }
098    }
099
100    public Map getThisScope() {
101        initCFC(null);
102        if(cfc==null)return null;
103        
104        Struct rtn=creator.createStruct();
105        Iterator<Entry<Key, Object>> it = cfc.entryIterator();
106        Entry<Key, Object> entry;
107        while(it.hasNext()){
108                entry = it.next();
109                rtn.setEL(entry.getKey(), entry.getValue());
110        }
111        return rtn;
112    }
113    
114    public final Object invoke(String methodName, Object args[]) throws Throwable {
115        if(invokeDirectly) return _invoke(methodName, args);
116        return _invoke(methodName, args, null, null, null);
117    }
118
119        public final Object invoke(String methodName, Object args[], HttpServletRequest request, HttpServletResponse response) throws Throwable {
120                if(invokeDirectly) return _invoke(methodName, args);
121        return _invoke(methodName, args, request, response, null);
122    }
123        
124    public final Object invoke(String methodName, Object args[], HttpServletRequest request, HttpServletResponse response, OutputStream out) throws Throwable {
125        if(invokeDirectly) return _invoke(methodName, args);
126        return _invoke(methodName, args, request, response, out);
127    }
128
129    public static boolean inInvoke() {
130        return false;
131    }
132
133    private Object _invoke(String methodName, Object[] args) throws PageException {
134        CFMLEngine engine = CFMLEngineFactory.getInstance();
135                PageContext pc = engine.getThreadPageContext();
136                initCFC(pc);
137        return cfc.call(pc, methodName, args);
138        }
139    
140    private Object _invoke(String methodName, Object[] args, HttpServletRequest req, HttpServletResponse rsp, OutputStream out) throws PageException {
141        CFMLEngine engine = CFMLEngineFactory.getInstance();
142                Creation creator = engine.getCreationUtil();
143                PageContext originalPC = engine.getThreadPageContext();
144                
145                // no OutputStream
146                if(out==null)out=DevNullOutputStream.DEV_NULL_OUTPUT_STREAM;
147                
148                // no Request
149                if(req==null){
150                        // TODO new File
151                        req=creator.createHttpServletRequest(new File("."), "Lucee", "/", "", null, null, null, null, null);
152                }
153                // noRespone
154                if(rsp==null){
155                        rsp=creator.createHttpServletResponse(out);
156                }
157                
158                
159                PageContext pc = creator.createPageContext(req,rsp,out);
160                try{
161                        engine.registerThreadPageContext(pc);
162                        initCFC(pc);
163                return cfc.call(pc, methodName, args);
164                }
165                finally{
166                        if(autoFlush) {
167                                try {
168                                        pc.getRootWriter().flush();
169                                } catch (Throwable t) {
170                                        if(t instanceof ThreadDeath) throw (ThreadDeath)t;
171                                }
172                        }
173                        engine.registerThreadPageContext(originalPC);
174                }
175        }
176
177    public void flush() throws IOException {
178        CFMLEngine engine = CFMLEngineFactory.getInstance();
179                PageContext pc = engine.getThreadPageContext();
180                pc.getRootWriter().flush();
181    }
182
183    public void setAutoFlush(boolean autoFlush) {
184        this.autoFlush = autoFlush;
185    }
186
187    public void setApplicationExecution(boolean doApp)
188    {
189        //executeApplication = doApp;
190    }
191
192}
193
194final class DevNullOutputStream extends OutputStream implements Serializable {
195        
196        public static final DevNullOutputStream DEV_NULL_OUTPUT_STREAM=new DevNullOutputStream();
197        
198        /**
199         * Constructor of the class
200         */
201        private DevNullOutputStream() {}
202        
203    /**
204     * @see java.io.OutputStream#close()
205     */
206    public void close(){}
207
208    /**
209     * @see java.io.OutputStream#flush()
210     */
211    public void flush() {}
212
213    /**
214     * @see java.io.OutputStream#write(byte[], int, int)
215     */
216    public void write(byte[] b, int off, int len) {}
217
218    /**
219     * @see java.io.OutputStream#write(byte[])
220     */
221    public void write(byte[] b) {}
222
223    /**
224     * @see java.io.OutputStream#write(int)
225     */
226    public void write(int b) {}
227
228}