package railo.runtime.engine; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; import railo.cli.servlet.HTTPServletImpl; import railo.commons.collection.MapFactory; import railo.commons.io.FileUtil; import railo.commons.io.IOUtil; import railo.commons.io.SystemUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.ResourceProvider; import railo.commons.io.res.ResourcesImpl; import railo.commons.io.res.util.ResourceUtil; import railo.commons.io.res.util.ResourceUtilImpl; import railo.commons.lang.Pair; import railo.commons.lang.StringUtil; import railo.commons.lang.SystemOut; import railo.commons.lang.types.RefBoolean; import railo.commons.lang.types.RefBooleanImpl; import railo.commons.net.HTTPUtil; import railo.intergral.fusiondebug.server.FDControllerImpl; import railo.loader.engine.CFMLEngine; import railo.loader.engine.CFMLEngineFactory; import railo.loader.engine.CFMLEngineWrapper; import railo.loader.util.Util; import railo.runtime.CFMLFactory; import railo.runtime.CFMLFactoryImpl; import railo.runtime.Info; import railo.runtime.PageContext; import railo.runtime.PageSource; import railo.runtime.config.ConfigServer; import railo.runtime.config.ConfigServerFactory; import railo.runtime.config.ConfigServerImpl; import railo.runtime.config.ConfigWeb; import railo.runtime.config.ConfigWebFactory; import railo.runtime.config.ConfigWebImpl; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.PageException; import railo.runtime.exp.PageServletException; import railo.runtime.net.http.HTTPServletRequestWrap; import railo.runtime.net.http.HttpServletRequestDummy; import railo.runtime.net.http.HttpServletResponseDummy; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.op.CastImpl; import railo.runtime.op.Caster; import railo.runtime.op.CreationImpl; import railo.runtime.op.DecisionImpl; import railo.runtime.op.ExceptonImpl; import railo.runtime.op.OperationImpl; import railo.runtime.query.QueryCacheSupport; import railo.runtime.type.StructImpl; import railo.runtime.util.BlazeDSImpl; import railo.runtime.util.Cast; import railo.runtime.util.Creation; import railo.runtime.util.Decision; import railo.runtime.util.Excepton; import railo.runtime.util.HTTPUtilImpl; import railo.runtime.util.Operation; import railo.runtime.util.ZipUtil; import railo.runtime.util.ZipUtilImpl; import railo.runtime.video.VideoUtil; import railo.runtime.video.VideoUtilImpl; import com.intergral.fusiondebug.server.FDControllerFactory; /** * The CFMl Engine */ public final class CFMLEngineImpl implements CFMLEngine { private static Map<String,CFMLFactory> initContextes=MapFactory.<String,CFMLFactory>getConcurrentMap(); private static Map<String,CFMLFactory> contextes=MapFactory.<String,CFMLFactory>getConcurrentMap(); private static ConfigServerImpl configServer=null; private static CFMLEngineImpl engine=null; //private ServletConfig config; private CFMLEngineFactory factory; private AMFEngine amfEngine=new AMFEngine(); private final RefBoolean controlerState=new RefBooleanImpl(true); private boolean allowRequestTimeout=true; private Monitor monitor; private List<ServletConfig> servletConfigs=new ArrayList<ServletConfig>(); private long uptime; //private static CFMLEngineImpl engine=new CFMLEngineImpl(); private CFMLEngineImpl(CFMLEngineFactory factory) { this.factory=factory; CFMLEngineFactory.registerInstance(this);// patch, not really good but it works ConfigServerImpl cs = getConfigServerImpl(); SystemOut.printDate(SystemUtil.getPrintWriter(SystemUtil.OUT),"Start CFML Controller"); Controler controler = new Controler(cs,initContextes,5*1000,controlerState); controler.setDaemon(true); controler.setPriority(Thread.MIN_PRIORITY); controler.start(); touchMonitor(cs); this.uptime=System.currentTimeMillis(); //this.config=config; } public void touchMonitor(ConfigServerImpl cs) { if(monitor!=null && monitor.isAlive()) return; monitor = new Monitor(cs,controlerState); monitor.setDaemon(true); monitor.setPriority(Thread.MIN_PRIORITY); monitor.start(); } /** * get singelton instance of the CFML Engine * @param factory * @return CFMLEngine */ public static synchronized CFMLEngine getInstance(CFMLEngineFactory factory) { if(engine==null) { engine=new CFMLEngineImpl(factory); } return engine; } /** * get singelton instance of the CFML Engine, throwsexception when not already init * @param factory * @return CFMLEngine */ public static synchronized CFMLEngine getInstance() throws ServletException { if(engine!=null) return engine; throw new ServletException("CFML Engine is not loaded"); } @Override public void addServletConfig(ServletConfig config) throws ServletException { servletConfigs.add(config); String real=ReqRspUtil.getRootPath(config.getServletContext()); if(!initContextes.containsKey(real)) { CFMLFactory jspFactory = loadJSPFactory(getConfigServerImpl(),config,initContextes.size()); initContextes.put(real,jspFactory); } } // FUTURE add to public interface public ConfigServer getConfigServer(String password) throws PageException { getConfigServerImpl().checkAccess(password); return getConfigServerImpl(); } // FUTURE add to public interface public ConfigServer getConfigServer(String key, long timeNonce) throws PageException { configServer.checkAccess(key,timeNonce); return configServer; } private ConfigServerImpl getConfigServerImpl() { if(configServer==null) { try { ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); Resource context = frp.getResource(factory.getResourceRoot().getAbsolutePath()).getRealResource("context"); //CFMLEngineFactory.registerInstance(this);// patch, not really good but it works configServer=ConfigServerFactory.newInstance( this, initContextes, contextes, context); } catch (Exception e) { e.printStackTrace(); } } return configServer; } private CFMLFactoryImpl loadJSPFactory(ConfigServerImpl configServer, ServletConfig sg, int countExistingContextes) throws ServletException { try { // Load Config RefBoolean isCustomSetting=new RefBooleanImpl(); Resource configDir=getConfigDirectory(sg,configServer,countExistingContextes,isCustomSetting); QueryCacheSupport queryCache=QueryCacheSupport.getInstance(); CFMLFactoryImpl factory=new CFMLFactoryImpl(this,queryCache); ConfigWebImpl config=ConfigWebFactory.newInstance(factory,configServer,configDir,isCustomSetting.toBooleanValue(),sg); factory.setConfig(config); return factory; } catch (Exception e) { ServletException se= new ServletException(e.getMessage()); se.setStackTrace(e.getStackTrace()); throw se; } } /** * loads Configuration File from System, from init Parameter from web.xml * @param sg * @param configServer * @param countExistingContextes * @return return path to directory */ private Resource getConfigDirectory(ServletConfig sg, ConfigServerImpl configServer, int countExistingContextes, RefBoolean isCustomSetting) throws PageServletException { isCustomSetting.setValue(true); ServletContext sc=sg.getServletContext(); String strConfig=sg.getInitParameter("configuration"); if(strConfig==null)strConfig=sg.getInitParameter("railo-web-directory"); if(strConfig==null) { isCustomSetting.setValue(false); strConfig="{web-root-directory}/WEB-INF/railo/"; } // only for backward compatibility else if(strConfig.startsWith("/WEB-INF/railo/"))strConfig="{web-root-directory}"+strConfig; strConfig=Util.removeQuotes(strConfig,true); // static path is not allowed if(countExistingContextes>1 && strConfig!=null && strConfig.indexOf('{')==-1){ String text="static path ["+strConfig+"] for servlet init param [railo-web-directory] is not allowed, path must use a web-context specific placeholder."; System.err.println(text); throw new PageServletException(new ApplicationException(text)); } strConfig=SystemUtil.parsePlaceHolder(strConfig,sc,configServer.getLabels()); ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); Resource root = frp.getResource(ReqRspUtil.getRootPath(sc)); Resource configDir=ResourceUtil.createResource(root.getRealResource(strConfig), FileUtil.LEVEL_PARENT_FILE,FileUtil.TYPE_DIR); if(configDir==null) { configDir=ResourceUtil.createResource(frp.getResource(strConfig), FileUtil.LEVEL_GRAND_PARENT_FILE,FileUtil.TYPE_DIR); } if(configDir==null) throw new PageServletException(new ApplicationException("path ["+strConfig+"] is invalid")); if(!configDir.exists()){ try { configDir.createDirectory(true); } catch (IOException e) {} } return configDir; } @Override public CFMLFactory getCFMLFactory(ServletContext srvContext, ServletConfig srvConfig,HttpServletRequest req) throws ServletException { String real=ReqRspUtil.getRootPath(srvContext); ConfigServerImpl cs = getConfigServerImpl(); // Load JspFactory CFMLFactoryImpl factory=null; Object o=contextes.get(real); if(o==null) { //int size=sn.getContextCount(); //if(size!=-1 && size <= contextes.size()) //throw new ServletException("the maximum size of "+size+" web contextes is reached, " +"to have more contexes upgrade your railo version, already contextes in use are ["+getContextList()+"]"); o=initContextes.get(real); if(o!=null) { factory=(CFMLFactoryImpl) o; } else { factory=loadJSPFactory(cs,srvConfig,initContextes.size()); initContextes.put(real,factory); } contextes.put(real,factory); try { String cp = req.getContextPath(); if(cp==null)cp=""; factory.setURL(new URL(req.getScheme(),req.getServerName(),req.getServerPort(),cp)); } catch (MalformedURLException e) { e.printStackTrace(); } // } else { factory=(CFMLFactoryImpl) o; } return factory; } @Override public void serviceCFML(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req); PageContext pc = factory.getRailoPageContext(servlet,req,rsp,null,false,-1,false); ThreadQueue queue = factory.getConfig().getThreadQueue(); queue.enter(pc); try { /*print.out("INCLUDE"); print.out("servlet_path:"+req.getAttribute("javax.servlet.include.servlet_path")); print.out("request_uri:"+req.getAttribute("javax.servlet.include.request_uri")); print.out("context_path:"+req.getAttribute("javax.servlet.include.context_path")); print.out("path_info:"+req.getAttribute("javax.servlet.include.path_info")); print.out("query_string:"+req.getAttribute("javax.servlet.include.query_string")); print.out("FORWARD"); print.out("servlet_path:"+req.getAttribute("javax.servlet.forward.servlet_path")); print.out("request_uri:"+req.getAttribute("javax.servlet.forward.request_uri")); print.out("context_path:"+req.getAttribute("javax.servlet.forward.context_path")); print.out("path_info:"+req.getAttribute("javax.servlet.forward.path_info")); print.out("query_string:"+req.getAttribute("javax.servlet.forward.query_string")); print.out("---"); print.out(req.getServletPath()); print.out(pc.getHttpServletRequest().getServletPath()); */ pc.execute(pc.getHttpServletRequest().getServletPath(),false); } catch (PageException pe) { throw new PageServletException(pe); } finally { queue.exit(pc); factory.releaseRailoPageContext(pc); FDControllerFactory.notifyPageComplete(); } } public void serviceFile(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { req=new HTTPServletRequestWrap(req); CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req); ConfigWeb config = factory.getConfig(); PageSource ps = config.getPageSourceExisting(null, null, req.getServletPath(), false, true, true, false); //Resource res = ((ConfigWebImpl)config).getPhysicalResourceExistingX(null, null, req.getServletPath(), false, true, true); if(ps==null) { rsp.sendError(404); } else { Resource res = ps.getResource(); if(res==null) { rsp.sendError(404); } else { ReqRspUtil.setContentLength(rsp,res.length()); String mt = servlet.getServletContext().getMimeType(req.getServletPath()); if(!StringUtil.isEmpty(mt))rsp.setContentType(mt); IOUtil.copy(res, rsp.getOutputStream(), true); } } } public void serviceRest(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { req=new HTTPServletRequestWrap(req); CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req); PageContext pc = factory.getRailoPageContext(servlet,req,rsp,null,false,-1,false); ThreadQueue queue = factory.getConfig().getThreadQueue(); queue.enter(pc); try { pc.executeRest(pc.getHttpServletRequest().getServletPath(),false); } catch (PageException pe) { throw new PageServletException(pe); } finally { queue.exit(pc); factory.releaseRailoPageContext(pc); FDControllerFactory.notifyPageComplete(); } } /*private String getContextList() { return List.arrayToList((String[])contextes.keySet().toArray(new String[contextes.size()]),", "); }*/ @Override public String getVersion() { return Info.getVersionAsString(); } @Override public String getUpdateType() { return getConfigServerImpl().getUpdateType(); } @Override public URL getUpdateLocation() { return getConfigServerImpl().getUpdateLocation(); } @Override public boolean can(int type, String password) { return getConfigServerImpl().passwordEqual(password); } public CFMLEngineFactory getCFMLEngineFactory() { return factory; } public void serviceAMF(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { req=new HTTPServletRequestWrap(req); amfEngine.service(servlet,req,rsp); } @Override public void reset() { reset(null); } @Override public void reset(String configId) { CFMLFactoryImpl cfmlFactory; //ScopeContext scopeContext; try { Iterator<String> it = contextes.keySet().iterator(); while(it.hasNext()) { try { cfmlFactory=(CFMLFactoryImpl) contextes.get(it.next()); if(configId!=null && !configId.equals(cfmlFactory.getConfigWebImpl().getId())) continue; // scopes try{cfmlFactory.getScopeContext().clear();}catch(Throwable t){t.printStackTrace();} // PageContext try{cfmlFactory.resetPageContext();}catch(Throwable t){t.printStackTrace();} // Query Cache try{ cfmlFactory.getDefaultQueryCache().clear(null);}catch(Throwable t){t.printStackTrace();} // Gateway try{ cfmlFactory.getConfigWebImpl().getGatewayEngine().reset();}catch(Throwable t){t.printStackTrace();} } catch(Throwable t){ t.printStackTrace(); } } } finally { // Controller controlerState.setValue(false); } } @Override public Cast getCastUtil() { return CastImpl.getInstance(); } @Override public Operation getOperatonUtil() { return OperationImpl.getInstance(); } @Override public Decision getDecisionUtil() { return DecisionImpl.getInstance(); } @Override public Excepton getExceptionUtil() { return ExceptonImpl.getInstance(); } @Override public Creation getCreationUtil() { return CreationImpl.getInstance(this); } @Override public Object getBlazeDSUtil() { return new BlazeDSImpl(); } @Override public Object getFDController() { engine.allowRequestTimeout(false); return new FDControllerImpl(engine,engine.getConfigServerImpl().getSerialNumber()); } public Map<String,CFMLFactory> getCFMLFactories() { return initContextes; } @Override public railo.runtime.util.ResourceUtil getResourceUtil() { return ResourceUtilImpl.getInstance(); } @Override public railo.runtime.util.HTTPUtil getHTTPUtil() { return HTTPUtilImpl.getInstance(); } @Override public PageContext getThreadPageContext() { return ThreadLocalPageContext.get(); } @Override public void registerThreadPageContext(PageContext pc) { ThreadLocalPageContext.register(pc); } @Override public VideoUtil getVideoUtil() { return VideoUtilImpl.getInstance(); } @Override public ZipUtil getZipUtil() { return ZipUtilImpl.getInstance(); } @Override public String getState() { return Info.getStateAsString(); } public void allowRequestTimeout(boolean allowRequestTimeout) { this.allowRequestTimeout=allowRequestTimeout; } public boolean allowRequestTimeout() { return allowRequestTimeout; } public boolean isRunning() { try{ CFMLEngine other = CFMLEngineFactory.getInstance(); // FUTURE patch, do better impl when changing loader if(other!=this && controlerState.toBooleanValue() && !(other instanceof CFMLEngineWrapper)) { SystemOut.printDate("CFMLEngine is still set to true but no longer valid, Railo disable this CFMLEngine."); controlerState.setValue(false); reset(); return false; } } catch(Throwable t){} return controlerState.toBooleanValue(); } @Override public void cli(Map<String, String> config, ServletConfig servletConfig) throws IOException,JspException,ServletException { ServletContext servletContext = servletConfig.getServletContext(); HTTPServletImpl servlet=new HTTPServletImpl(servletConfig, servletContext, servletConfig.getServletName()); // webroot String strWebroot=config.get("webroot"); if(Util.isEmpty(strWebroot,true)) throw new IOException("missing webroot configuration"); Resource root=ResourcesImpl.getFileResourceProvider().getResource(strWebroot); root.mkdirs(); // serverName String serverName=config.get("server-name"); if(Util.isEmpty(serverName,true))serverName="localhost"; // uri String strUri=config.get("uri"); if(Util.isEmpty(strUri,true)) throw new IOException("missing uri configuration"); URI uri; try { uri = railo.commons.net.HTTPUtil.toURI(strUri); } catch (URISyntaxException e) { throw Caster.toPageException(e); } // cookie Cookie[] cookies; String strCookie=config.get("cookie"); if(Util.isEmpty(strCookie,true)) cookies=new Cookie[0]; else { Map<String,String> mapCookies=HTTPUtil.parseParameterList(strCookie,false,null); int index=0; cookies=new Cookie[mapCookies.size()]; Entry<String, String> entry; Iterator<Entry<String, String>> it = mapCookies.entrySet().iterator(); while(it.hasNext()){ entry = it.next(); cookies[index++]=new Cookie(entry.getKey(),entry.getValue()); } } // header Pair[] headers=new Pair[0]; // parameters Pair[] parameters=new Pair[0]; // attributes StructImpl attributes = new StructImpl(); ByteArrayOutputStream os=new ByteArrayOutputStream(); HttpServletRequestDummy req=new HttpServletRequestDummy( root,serverName,uri.getPath(),uri.getQuery(),cookies,headers,parameters,attributes,null); req.setProtocol("CLI/1.0"); HttpServletResponse rsp=new HttpServletResponseDummy(os); serviceCFML(servlet, req, rsp); String res = os.toString(ReqRspUtil.getCharacterEncoding(null,rsp)); System.out.println(res); } public ServletConfig[] getServletConfigs(){ return servletConfigs.toArray(new ServletConfig[servletConfigs.size()]); } // FUTURE add to interface public long uptime() { return uptime; } }