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.engine;
020
021import java.io.ByteArrayInputStream;
022import java.io.ByteArrayOutputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.io.OutputStream;
026import java.net.MalformedURLException;
027import java.net.URI;
028import java.net.URISyntaxException;
029import java.net.URL;
030import java.util.ArrayList;
031import java.util.Iterator;
032import java.util.List;
033import java.util.Map;
034import java.util.Map.Entry;
035
036import javax.servlet.ServletConfig;
037import javax.servlet.ServletContext;
038import javax.servlet.ServletException;
039import javax.servlet.http.Cookie;
040import javax.servlet.http.HttpServlet;
041import javax.servlet.http.HttpServletRequest;
042import javax.servlet.http.HttpServletResponse;
043import javax.servlet.jsp.JspException;
044
045import lucee.cli.servlet.HTTPServletImpl;
046import lucee.commons.collection.MapFactory;
047import lucee.commons.io.CompressUtil;
048import lucee.commons.io.FileUtil;
049import lucee.commons.io.IOUtil;
050import lucee.commons.io.SystemUtil;
051import lucee.commons.io.res.Resource;
052import lucee.commons.io.res.ResourceProvider;
053import lucee.commons.io.res.ResourcesImpl;
054import lucee.commons.io.res.util.ResourceUtil;
055import lucee.commons.io.res.util.ResourceUtilImpl;
056import lucee.commons.lang.ExceptionUtil;
057import lucee.commons.lang.Pair;
058import lucee.commons.lang.StringUtil;
059import lucee.commons.lang.SystemOut;
060import lucee.commons.lang.types.RefBoolean;
061import lucee.commons.lang.types.RefBooleanImpl;
062import lucee.commons.net.HTTPUtil;
063import lucee.intergral.fusiondebug.server.FDControllerImpl;
064import lucee.loader.engine.CFMLEngine;
065import lucee.loader.engine.CFMLEngineFactory;
066import lucee.loader.engine.CFMLEngineWrapper;
067import lucee.loader.util.Util;
068import lucee.runtime.CFMLFactory;
069import lucee.runtime.CFMLFactoryImpl;
070import lucee.runtime.Info;
071import lucee.runtime.PageContext;
072import lucee.runtime.PageSource;
073import lucee.runtime.config.ConfigServer;
074import lucee.runtime.config.ConfigServerFactory;
075import lucee.runtime.config.ConfigServerImpl;
076import lucee.runtime.config.ConfigWeb;
077import lucee.runtime.config.ConfigWebFactory;
078import lucee.runtime.config.ConfigWebImpl;
079import lucee.runtime.config.ConfigWebUtil;
080import lucee.runtime.exp.ApplicationException;
081import lucee.runtime.exp.PageException;
082import lucee.runtime.exp.PageServletException;
083import lucee.runtime.net.http.HTTPServletRequestWrap;
084import lucee.runtime.net.http.HttpServletRequestDummy;
085import lucee.runtime.net.http.HttpServletResponseDummy;
086import lucee.runtime.net.http.ReqRspUtil;
087import lucee.runtime.op.CastImpl;
088import lucee.runtime.op.Caster;
089import lucee.runtime.op.CreationImpl;
090import lucee.runtime.op.DecisionImpl;
091import lucee.runtime.op.ExceptonImpl;
092import lucee.runtime.op.OperationImpl;
093import lucee.runtime.type.StructImpl;
094import lucee.runtime.util.BlazeDSImpl;
095import lucee.runtime.util.Cast;
096import lucee.runtime.util.Creation;
097import lucee.runtime.util.Decision;
098import lucee.runtime.util.Excepton;
099import lucee.runtime.util.HTTPUtilImpl;
100import lucee.runtime.util.Operation;
101import lucee.runtime.util.ZipUtil;
102import lucee.runtime.util.ZipUtilImpl;
103import lucee.runtime.video.VideoUtil;
104import lucee.runtime.video.VideoUtilImpl;
105
106import com.intergral.fusiondebug.server.FDControllerFactory;
107
108/**
109 * The CFMl Engine
110 */
111public final class CFMLEngineImpl implements CFMLEngine {
112        
113        
114        private static Map<String,CFMLFactory> initContextes=MapFactory.<String,CFMLFactory>getConcurrentMap();
115    private static Map<String,CFMLFactory> contextes=MapFactory.<String,CFMLFactory>getConcurrentMap();
116    private ConfigServerImpl configServer=null;
117    private static CFMLEngineImpl engine=null;
118    //private ServletConfig config;
119    private CFMLEngineFactory factory;
120    private AMFEngine amfEngine=new AMFEngine();
121    private final RefBoolean controlerState=new RefBooleanImpl(true);
122        private boolean allowRequestTimeout=true;
123        private Monitor monitor;
124        private List<ServletConfig> servletConfigs=new ArrayList<ServletConfig>();
125        private long uptime; 
126        
127    
128    //private static CFMLEngineImpl engine=new CFMLEngineImpl();
129
130    private CFMLEngineImpl(CFMLEngineFactory factory) {
131        this.factory=factory; 
132        CFMLEngineFactory.registerInstance(this);// patch, not really good but it works
133        ConfigServerImpl cs = getConfigServerImpl();
134        
135        SystemOut.printDate(SystemUtil.getPrintWriter(SystemUtil.OUT),"Start CFML Controller");
136        Controler controler = new Controler(cs,initContextes,5*1000,controlerState);
137        controler.setDaemon(true);
138        controler.setPriority(Thread.MIN_PRIORITY);
139        controler.start();
140
141        touchMonitor(cs);  
142        this.uptime=System.currentTimeMillis();
143        //this.config=config; 
144    }
145
146
147        public void touchMonitor(ConfigServerImpl cs) {
148                if(monitor!=null && monitor.isAlive()) return; 
149                monitor = new Monitor(cs,controlerState); 
150        monitor.setDaemon(true);
151        monitor.setPriority(Thread.MIN_PRIORITY);
152        monitor.start(); 
153        }
154
155    /**
156     * get singelton instance of the CFML Engine
157     * @param factory
158     * @return CFMLEngine
159     */
160    public static synchronized CFMLEngine getInstance(CFMLEngineFactory factory) {
161        if(engine==null) {
162                engine=new CFMLEngineImpl(factory);
163        }
164        return engine;
165    }
166    
167    /**
168     * get singelton instance of the CFML Engine, throwsexception when not already init
169     * @param factory
170     * @return CFMLEngine
171     */
172    public static synchronized CFMLEngine getInstance() throws ServletException {
173        if(engine!=null) return engine;
174        throw new ServletException("CFML Engine is not loaded");
175    }
176    
177    @Override
178    public void addServletConfig(ServletConfig config) throws ServletException {
179        servletConfigs.add(config);
180        String real=ReqRspUtil.getRootPath(config.getServletContext());
181        if(!initContextes.containsKey(real)) {             
182                CFMLFactory jspFactory = loadJSPFactory(getConfigServerImpl(),config,initContextes.size());
183            initContextes.put(real,jspFactory);
184        }        
185    }
186    
187    // FUTURE add to public interface
188    public ConfigServer getConfigServer(String password) throws PageException {
189        getConfigServerImpl().checkAccess(password);
190        return configServer;
191    }
192
193    // FUTURE add to public interface
194    public ConfigServer getConfigServer(String key, long timeNonce) throws PageException {
195        getConfigServerImpl().checkAccess(key,timeNonce);
196        return configServer;
197    }
198    
199    public void setConfigServerImpl(ConfigServerImpl cs) {
200        this.configServer=cs;
201    }
202
203    private ConfigServerImpl getConfigServerImpl() {
204        if(configServer==null) {
205            try {
206                ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
207                Resource context = frp.getResource(factory.getResourceRoot().getAbsolutePath()).getRealResource("context");
208                //CFMLEngineFactory.registerInstance(this);// patch, not really good but it works
209                configServer=ConfigServerFactory.newInstance(
210                        this,
211                        initContextes,
212                        contextes,
213                        context);
214            } catch (Exception e) {
215                e.printStackTrace();
216            }
217        }
218        return configServer;
219    }
220    
221    private  CFMLFactoryImpl loadJSPFactory(ConfigServerImpl configServer, ServletConfig sg, int countExistingContextes) throws ServletException {
222        try {
223            // Load Config
224                RefBoolean isCustomSetting=new RefBooleanImpl();
225            Resource configDir=getConfigDirectory(sg,configServer,countExistingContextes,isCustomSetting);
226            
227            CFMLFactoryImpl factory=new CFMLFactoryImpl(this);
228            ConfigWebImpl config=ConfigWebFactory.newInstance(factory,configServer,configDir,isCustomSetting.toBooleanValue(),sg);
229            factory.setConfig(config);
230            return factory;
231        }
232        catch (Exception e) {
233            ServletException se= new ServletException(e.getMessage());
234            se.setStackTrace(e.getStackTrace());
235            throw se;
236        } 
237        
238    }   
239
240    /**
241     * loads Configuration File from System, from init Parameter from web.xml
242     * @param sg
243     * @param configServer 
244     * @param countExistingContextes 
245     * @return return path to directory
246     */
247    private Resource getConfigDirectory(ServletConfig sg, ConfigServerImpl configServer, int countExistingContextes, RefBoolean isCustomSetting) throws PageServletException {
248        isCustomSetting.setValue(true);
249        ServletContext sc=sg.getServletContext();
250        String strConfig=sg.getInitParameter("configuration");
251        if(strConfig==null)strConfig=sg.getInitParameter("lucee-web-directory");
252        if(strConfig==null)strConfig=sg.getInitParameter("railo-web-directory");
253        if(strConfig==null) {
254                isCustomSetting.setValue(false);
255                strConfig="{web-root-directory}/WEB-INF/lucee/";
256        }
257        // only for backward compatibility
258        else if(strConfig.startsWith("/WEB-INF/railo/")) {
259                strConfig="{web-root-directory}"+strConfig;
260                strConfig=strConfig.replace("/railo/", "/lucee/");
261        }
262        
263        
264        strConfig=Util.removeQuotes(strConfig,true);
265        
266        
267        
268        // static path is not allowed
269        if(countExistingContextes>1 && strConfig!=null && strConfig.indexOf('{')==-1){
270                String text="static path ["+strConfig+"] for servlet init param [lucee-web-directory] is not allowed, path must use a web-context specific placeholder.";
271                System.err.println(text);
272                throw new PageServletException(new ApplicationException(text));
273        }
274        strConfig=SystemUtil.parsePlaceHolder(strConfig,sc,configServer.getLabels());
275        
276        
277        
278        ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
279        Resource root = frp.getResource(ReqRspUtil.getRootPath(sc));
280        Resource configDir=ResourceUtil.createResource(root.getRealResource(strConfig), FileUtil.LEVEL_PARENT_FILE,FileUtil.TYPE_DIR);
281        
282        if(configDir==null) {
283            configDir=ResourceUtil.createResource(frp.getResource(strConfig), FileUtil.LEVEL_GRAND_PARENT_FILE,FileUtil.TYPE_DIR);
284        }
285        if(configDir==null) throw new PageServletException(new ApplicationException("path ["+strConfig+"] is invalid"));
286                
287        if(!configDir.exists() || ResourceUtil.isEmptyDirectory(configDir, null)){
288                Resource railoRoot;
289                // there is a railo directory
290                if(configDir.getName().equals("lucee") && (railoRoot=configDir.getParentResource().getRealResource("railo")).isDirectory()) {
291                        try {
292                                        copyRecursiveAndRename(railoRoot,configDir);
293                                }
294                                catch (IOException e) {
295                                        try {
296                                        configDir.createDirectory(true);
297                                } 
298                        catch (IOException ioe) {}
299                                        return configDir;
300                                }
301                                // zip the railo-server di and delete it (optional)
302                                try {
303                                        Resource p=railoRoot.getParentResource();
304                                        CompressUtil.compress(CompressUtil.FORMAT_ZIP, railoRoot, p.getRealResource("railo-web-context-old.zip"), false, -1);
305                                        ResourceUtil.removeEL(railoRoot, true);
306                                }
307                                catch(Throwable t){
308                        ExceptionUtil.rethrowIfNecessary(t);
309                        t.printStackTrace();
310                    }
311                }
312                else {
313                try {
314                                configDir.createDirectory(true);
315                        } 
316                catch (IOException e) {}
317                        
318                }
319                
320        }
321        
322        return configDir;
323    }
324    
325    private static void copyRecursiveAndRename(Resource src,Resource trg) throws IOException {
326                if(!src.exists()) return ;
327                if(src.isDirectory()) {
328                        if(!trg.exists())trg.mkdirs();
329                        
330                        Resource[] files = src.listResources();
331                                for(int i=0;i<files.length;i++) {
332                                        copyRecursiveAndRename(files[i],trg.getRealResource(files[i].getName()));
333                                }
334                }
335                else if(src.isFile()) {
336                        if(trg.getName().endsWith(".rc") || trg.getName().startsWith(".")) {
337                                return;
338                        }
339                                        
340                        if(trg.getName().equals("railo-web.xml.cfm")) {
341                                trg=trg.getParentResource().getRealResource("lucee-web.xml.cfm");
342                                // cfLuceeConfiguration
343                                InputStream is = src.getInputStream();
344                                OutputStream os = trg.getOutputStream();
345                                        try{
346                                                String str=Util.toString(is);
347                                                str=str.replace("<cfRailoConfiguration", "<!-- copy from Railo context --><cfLuceeConfiguration");
348                                                str=str.replace("</cfRailoConfiguration", "</cfLuceeConfiguration");
349                                                str=str.replace("<railo-configuration", "<lucee-configuration");
350                                                str=str.replace("</railo-configuration", "</lucee-configuration");
351                                                str=str.replace("{railo-config}", "{lucee-config}");
352                                                str=str.replace("{railo-server}", "{lucee-server}");
353                                                str=str.replace("{railo-web}", "{lucee-web}");
354                                                str=str.replace("\"railo.commons.", "\"lucee.commons.");
355                                                str=str.replace("\"railo.runtime.", "\"lucee.runtime.");
356                                                str=str.replace("\"railo.cfx.", "\"lucee.cfx.");
357                                                str=str.replace("/railo-context.ra", "/lucee-context.lar");
358                                                str=str.replace("/railo-context", "/lucee");
359                                                str=str.replace("railo-server-context", "lucee-server");
360                                                str=str.replace("http://www.getrailo.org", "http://stable.lucee.org");
361                                                str=str.replace("http://www.getrailo.com", "http://stable.lucee.org");
362                                                
363                                                
364                                                ByteArrayInputStream bais = new ByteArrayInputStream(str.getBytes());
365                                                
366                                                try {
367                                                        Util.copy(bais, os);
368                                                        bais.close();
369                                                }
370                                                finally {
371                                                        Util.closeEL(is, os);
372                                                }
373                                        }
374                                        finally {
375                                                Util.closeEL(is,os);
376                                        }
377                                return;
378                        }
379
380                        InputStream is = src.getInputStream();
381                        OutputStream os = trg.getOutputStream();
382                        try{
383                                Util.copy(is, os);
384                        }
385                        finally {
386                                Util.closeEL(is, os);
387                        }
388                }
389         }
390         
391
392
393        @Override
394    
395    public CFMLFactory getCFMLFactory(ServletContext srvContext, ServletConfig srvConfig,HttpServletRequest req) throws ServletException {
396        String real=ReqRspUtil.getRootPath(srvContext);
397        ConfigServerImpl cs = getConfigServerImpl();
398        
399        
400        // Load JspFactory
401        CFMLFactoryImpl factory=null;
402        Object o=contextes.get(real);
403        if(o==null) {
404            //int size=sn.getContextCount();
405            //if(size!=-1 && size <= contextes.size())
406                //throw new ServletException("the maximum size of "+size+" web contextes is reached, " +"to have more contexes upgrade your lucee version, already contextes in use are ["+getContextList()+"]");
407            o=initContextes.get(real);
408            if(o!=null) {
409                factory=(CFMLFactoryImpl) o;
410            }
411            else {
412                factory=loadJSPFactory(cs,srvConfig,initContextes.size());
413                initContextes.put(real,factory);
414            }
415            contextes.put(real,factory);
416            
417            try {
418                String cp = req.getContextPath();
419                if(cp==null)cp="";
420                                factory.setURL(new URL(req.getScheme(),req.getServerName(),req.getServerPort(),cp));
421                        } 
422            catch (MalformedURLException e) {
423                                e.printStackTrace();
424                        }
425            //
426            
427        }
428        else {
429            factory=(CFMLFactoryImpl) o;
430        }
431        return factory;
432    }
433    
434    @Override
435    public void serviceCFML(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
436        
437        CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req);
438        
439        PageContext pc = factory.getLuceePageContext(servlet,req,rsp,null,false,-1,false);
440        ThreadQueue queue = factory.getConfig().getThreadQueue();
441        queue.enter(pc);
442        try {
443                /*print.out("INCLUDE");
444                print.out("servlet_path:"+req.getAttribute("javax.servlet.include.servlet_path"));
445                print.out("request_uri:"+req.getAttribute("javax.servlet.include.request_uri"));
446                print.out("context_path:"+req.getAttribute("javax.servlet.include.context_path"));
447                print.out("path_info:"+req.getAttribute("javax.servlet.include.path_info"));
448                print.out("query_string:"+req.getAttribute("javax.servlet.include.query_string"));
449                print.out("FORWARD");
450                print.out("servlet_path:"+req.getAttribute("javax.servlet.forward.servlet_path"));
451                print.out("request_uri:"+req.getAttribute("javax.servlet.forward.request_uri"));
452                print.out("context_path:"+req.getAttribute("javax.servlet.forward.context_path"));
453                print.out("path_info:"+req.getAttribute("javax.servlet.forward.path_info"));
454                print.out("query_string:"+req.getAttribute("javax.servlet.forward.query_string"));
455                print.out("---");
456                print.out(req.getServletPath());
457                print.out(pc.getHttpServletRequest().getServletPath());
458                */
459                
460                pc.execute(pc.getHttpServletRequest().getServletPath(),false);
461        } 
462        catch (PageException pe) {
463                        throw new PageServletException(pe);
464                }
465        finally {
466                queue.exit(pc);
467            factory.releaseLuceePageContext(pc);
468            FDControllerFactory.notifyPageComplete();
469        }
470    }
471
472        public void serviceFile(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
473                req=new HTTPServletRequestWrap(req);
474                CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req);
475        ConfigWeb config = factory.getConfig();
476        PageSource ps = config.getPageSourceExisting(null, null, req.getServletPath(), false, true, true, false);
477        //Resource res = ((ConfigWebImpl)config).getPhysicalResourceExistingX(null, null, req.getServletPath(), false, true, true); 
478        
479                if(ps==null) {
480                rsp.sendError(404);
481        }
482        else {
483                Resource res = ps.getResource();
484                if(res==null) {
485                        rsp.sendError(404);
486                }
487                else {
488                        ReqRspUtil.setContentLength(rsp,res.length());
489                        String mt = servlet.getServletContext().getMimeType(req.getServletPath());
490                        if(!StringUtil.isEmpty(mt))rsp.setContentType(mt);
491                        IOUtil.copy(res, rsp.getOutputStream(), true);
492                }
493        }
494        }
495        
496
497        public void serviceRest(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
498                req=new HTTPServletRequestWrap(req);
499                CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req);
500        
501                PageContext pc = factory.getLuceePageContext(servlet,req,rsp,null,false,-1,false);
502        ThreadQueue queue = factory.getConfig().getThreadQueue();
503        queue.enter(pc);
504        try {
505                pc.executeRest(pc.getHttpServletRequest().getServletPath(),false);
506        } 
507        catch (PageException pe) {
508                        throw new PageServletException(pe);
509                }
510        finally {
511                queue.exit(pc);
512            factory.releaseLuceePageContext(pc);
513            FDControllerFactory.notifyPageComplete();
514        }
515                
516                
517        }
518    
519
520    /*private String getContextList() {
521        return List.arrayToList((String[])contextes.keySet().toArray(new String[contextes.size()]),", ");
522    }*/
523
524    @Override
525    public String getVersion() {
526        return Info.getVersionAsString();
527    }
528
529    @Override
530    public String getUpdateType() {
531        return getConfigServerImpl().getUpdateType();
532    }
533
534    @Override
535    public URL getUpdateLocation() {
536        return getConfigServerImpl().getUpdateLocation();
537    }
538
539    @Override
540    public boolean can(int type, String password) {
541        return getConfigServerImpl().passwordEqual(password);
542    }
543
544    public CFMLEngineFactory getCFMLEngineFactory() {
545        return factory;
546    }
547
548    public void serviceAMF(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
549        req=new HTTPServletRequestWrap(req);
550                amfEngine.service(servlet,req,rsp);
551    }
552
553    @Override
554    public void reset() {
555        reset(null);
556    }
557    
558    @Override
559    public void reset(String configId) {
560        
561        CFMLFactoryImpl cfmlFactory;
562        //ScopeContext scopeContext;
563        try {
564                Iterator<String> it = contextes.keySet().iterator();
565                while(it.hasNext()) {
566                        try {
567                            cfmlFactory=(CFMLFactoryImpl) contextes.get(it.next());
568                            if(configId!=null && !configId.equals(cfmlFactory.getConfigWebImpl().getId())) continue;
569                                
570                            // scopes
571                            try{
572                                cfmlFactory.getScopeContext().clear();
573                            }catch(Throwable t){
574                                ExceptionUtil.rethrowIfNecessary(t);
575                                t.printStackTrace();
576                            }
577                            
578                            // PageContext
579                            try{
580                                cfmlFactory.resetPageContext();
581                            }catch(Throwable t){
582                                ExceptionUtil.rethrowIfNecessary(t);
583                                t.printStackTrace();
584                            }
585                            
586                            // Query Cache
587                            try{ 
588                                PageContext pc = ThreadLocalPageContext.get();
589                                if(pc!=null) {
590                                        ConfigWebUtil.getCacheHandlerFactories(pc.getConfig()).query.clear(pc);
591                                        ConfigWebUtil.getCacheHandlerFactories(pc.getConfig()).function.clear(pc);
592                                        ConfigWebUtil.getCacheHandlerFactories(pc.getConfig()).include.clear(pc);
593                                }
594                                //cfmlFactory.getDefaultQueryCache().clear(null);
595                            }catch(Throwable t){
596                                ExceptionUtil.rethrowIfNecessary(t);
597                                t.printStackTrace();
598                            }
599                            
600                            // Gateway
601                            try{ cfmlFactory.getConfigWebImpl().getGatewayEngine().reset();}catch(Throwable t){ExceptionUtil.rethrowIfNecessary(t);t.printStackTrace();}
602                            
603                        }
604                        catch(Throwable t){
605                        ExceptionUtil.rethrowIfNecessary(t);
606                                t.printStackTrace();
607                        }
608                }
609        }
610        finally {
611            // Controller
612            controlerState.setValue(false);
613        }
614    }
615    
616    @Override
617    public Cast getCastUtil() {
618        return CastImpl.getInstance();
619    }
620
621    @Override
622    public Operation getOperatonUtil() {
623        return OperationImpl.getInstance();
624    }
625
626    @Override
627    public Decision getDecisionUtil() {
628        return DecisionImpl.getInstance();
629    }
630
631    @Override
632    public Excepton getExceptionUtil() {
633        return ExceptonImpl.getInstance();
634    }
635
636    @Override
637    public Creation getCreationUtil() {
638        return CreationImpl.getInstance(this);
639    }
640
641        @Override
642        public Object getBlazeDSUtil() {
643                return new BlazeDSImpl();
644        }
645
646        @Override
647        public Object getFDController() {
648                engine.allowRequestTimeout(false);
649                
650                return new FDControllerImpl(engine,engine.getConfigServerImpl().getSerialNumber());
651        }
652
653        public Map<String,CFMLFactory> getCFMLFactories() {
654                return initContextes;
655        }
656
657        @Override
658        public lucee.runtime.util.ResourceUtil getResourceUtil() {
659                return ResourceUtilImpl.getInstance();
660        }
661
662        @Override
663        public lucee.runtime.util.HTTPUtil getHTTPUtil() {
664                return HTTPUtilImpl.getInstance();
665        }
666
667        @Override
668        public PageContext getThreadPageContext() {
669                return ThreadLocalPageContext.get();
670        }
671
672        @Override
673        public void registerThreadPageContext(PageContext pc) {
674                ThreadLocalPageContext.register(pc);
675        }
676
677        @Override
678        public VideoUtil getVideoUtil() {
679                return VideoUtilImpl.getInstance();
680        }
681
682        @Override
683        public ZipUtil getZipUtil() {
684                return ZipUtilImpl.getInstance();
685        }
686
687        @Override
688        public String getState() {
689                return Info.getStateAsString();
690        }
691
692        public void allowRequestTimeout(boolean allowRequestTimeout) {
693                this.allowRequestTimeout=allowRequestTimeout;
694        }
695
696        public boolean allowRequestTimeout() {
697                return allowRequestTimeout;
698        }
699        
700        public boolean isRunning() {
701                try{
702                        CFMLEngine other = CFMLEngineFactory.getInstance();
703                        // FUTURE patch, do better impl when changing loader
704                        if(other!=this && controlerState.toBooleanValue() &&  !(other instanceof CFMLEngineWrapper)) {
705                                SystemOut.printDate("CFMLEngine is still set to true but no longer valid, Lucee disable this CFMLEngine.");
706                                controlerState.setValue(false);
707                                reset();
708                                return false;
709                        }
710                }
711                catch(Throwable t){
712                ExceptionUtil.rethrowIfNecessary(t);
713        }
714                return controlerState.toBooleanValue();
715        }
716
717        @Override
718        public void cli(Map<String, String> config, ServletConfig servletConfig) throws IOException,JspException,ServletException {
719                ServletContext servletContext = servletConfig.getServletContext();
720                HTTPServletImpl servlet=new HTTPServletImpl(servletConfig, servletContext, servletConfig.getServletName());
721
722                // webroot
723                String strWebroot=config.get("webroot");
724                if(Util.isEmpty(strWebroot,true)) throw new IOException("missing webroot configuration");
725                Resource root=ResourcesImpl.getFileResourceProvider().getResource(strWebroot);
726                root.mkdirs();
727                
728                // serverName
729                String serverName=config.get("server-name");
730                if(Util.isEmpty(serverName,true))serverName="localhost";
731                
732                // uri
733                String strUri=config.get("uri");
734                if(Util.isEmpty(strUri,true)) throw new IOException("missing uri configuration");
735                URI uri;
736                try {
737                        uri = lucee.commons.net.HTTPUtil.toURI(strUri);
738                } catch (URISyntaxException e) {
739                        throw Caster.toPageException(e);
740                }
741                
742                // cookie
743                Cookie[] cookies;
744                String strCookie=config.get("cookie");
745                if(Util.isEmpty(strCookie,true)) cookies=new Cookie[0];
746                else {
747                        Map<String,String> mapCookies=HTTPUtil.parseParameterList(strCookie,false,null);
748                        int index=0;
749                        cookies=new Cookie[mapCookies.size()];
750                        Entry<String, String> entry;
751                        Iterator<Entry<String, String>> it = mapCookies.entrySet().iterator();
752                        Cookie c;
753                        while(it.hasNext()){
754                                entry = it.next();
755                                c=ReqRspUtil.toCookie(entry.getKey(),entry.getValue(),null);
756                                if(c!=null)cookies[index++]=c;
757                                else throw new IOException("Cookie name ["+entry.getKey()+"] is invalid");
758                        }
759                }
760                
761
762                // header
763                Pair[] headers=new Pair[0];
764                
765                // parameters
766                Pair[] parameters=new Pair[0];
767                
768                // attributes
769                StructImpl attributes = new StructImpl();
770                ByteArrayOutputStream os=new ByteArrayOutputStream();
771                
772                
773                
774                
775                HttpServletRequestDummy req=new HttpServletRequestDummy(
776                                root,serverName,uri.getPath(),uri.getQuery(),cookies,headers,parameters,attributes,null);
777                req.setProtocol("CLI/1.0");
778                HttpServletResponse rsp=new HttpServletResponseDummy(os);
779                
780                serviceCFML(servlet, req, rsp);
781                String res = os.toString(ReqRspUtil.getCharacterEncoding(null,rsp).name());
782                System.out.println(res);
783        }
784        
785        public ServletConfig[] getServletConfigs(){
786                return servletConfigs.toArray(new ServletConfig[servletConfigs.size()]);
787        }
788
789        // FUTURE add to interface
790        public long uptime() {
791                return uptime;
792        }
793
794}