001 package railo.runtime.engine; 002 003 import java.io.IOException; 004 import java.net.MalformedURLException; 005 import java.net.URL; 006 import java.util.Iterator; 007 import java.util.Map; 008 009 import javax.servlet.ServletConfig; 010 import javax.servlet.ServletContext; 011 import javax.servlet.ServletException; 012 import javax.servlet.http.HttpServlet; 013 import javax.servlet.http.HttpServletRequest; 014 import javax.servlet.http.HttpServletResponse; 015 016 import railo.commons.collections.HashTable; 017 import railo.commons.io.FileUtil; 018 import railo.commons.io.IOUtil; 019 import railo.commons.io.SystemUtil; 020 import railo.commons.io.res.Resource; 021 import railo.commons.io.res.ResourceProvider; 022 import railo.commons.io.res.ResourcesImpl; 023 import railo.commons.io.res.util.ResourceUtil; 024 import railo.commons.io.res.util.ResourceUtilImpl; 025 import railo.commons.lang.StringUtil; 026 import railo.commons.lang.SystemOut; 027 import railo.commons.lang.types.RefBoolean; 028 import railo.commons.lang.types.RefBooleanImpl; 029 import railo.intergral.fusiondebug.server.FDControllerImpl; 030 import railo.loader.engine.CFMLEngine; 031 import railo.loader.engine.CFMLEngineFactory; 032 import railo.loader.engine.CFMLEngineWrapper; 033 import railo.runtime.CFMLFactory; 034 import railo.runtime.CFMLFactoryImpl; 035 import railo.runtime.Info; 036 import railo.runtime.PageContext; 037 import railo.runtime.config.ConfigServerFactory; 038 import railo.runtime.config.ConfigServerImpl; 039 import railo.runtime.config.ConfigWeb; 040 import railo.runtime.config.ConfigWebFactory; 041 import railo.runtime.config.ConfigWebImpl; 042 import railo.runtime.exp.ApplicationException; 043 import railo.runtime.exp.PageException; 044 import railo.runtime.exp.PageServletException; 045 import railo.runtime.net.http.HTTPServletRequestWrap; 046 import railo.runtime.net.http.ReqRspUtil; 047 import railo.runtime.op.CastImpl; 048 import railo.runtime.op.CreationImpl; 049 import railo.runtime.op.DecisionImpl; 050 import railo.runtime.op.ExceptonImpl; 051 import railo.runtime.op.OperationImpl; 052 import railo.runtime.query.QueryCacheSupport; 053 import railo.runtime.util.BlazeDSImpl; 054 import railo.runtime.util.Cast; 055 import railo.runtime.util.Creation; 056 import railo.runtime.util.Decision; 057 import railo.runtime.util.Excepton; 058 import railo.runtime.util.HTTPUtil; 059 import railo.runtime.util.HTTPUtilImpl; 060 import railo.runtime.util.Operation; 061 import railo.runtime.util.ZipUtil; 062 import railo.runtime.util.ZipUtilImpl; 063 import railo.runtime.video.VideoUtil; 064 import railo.runtime.video.VideoUtilImpl; 065 066 import com.intergral.fusiondebug.server.FDControllerFactory; 067 068 /** 069 * The CFMl Engine 070 */ 071 public final class CFMLEngineImpl implements CFMLEngine { 072 073 074 private static Map initContextes=new HashTable(); 075 private static Map contextes=new HashTable(); 076 private static ConfigServerImpl configServer=null; 077 private static CFMLEngineImpl engine=null; 078 //private ServletConfig config; 079 private CFMLEngineFactory factory; 080 private AMFEngine amfEngine=new AMFEngine(); 081 private final RefBoolean controlerState=new RefBooleanImpl(true); 082 private boolean allowRequestTimeout=true; 083 private Monitor monitor; 084 085 //private static CFMLEngineImpl engine=new CFMLEngineImpl(); 086 087 private CFMLEngineImpl(CFMLEngineFactory factory) { 088 this.factory=factory; 089 CFMLEngineFactory.registerInstance(this);// patch, not really good but it works 090 ConfigServerImpl cs = getConfigServerImpl(); 091 092 SystemOut.printDate(SystemUtil.PRINTWRITER_OUT,"Start CFML Controller"); 093 Controler controler = new Controler(cs,initContextes,5*1000,controlerState); 094 controler.setDaemon(true); 095 controler.setPriority(Thread.MIN_PRIORITY); 096 controler.start(); 097 098 099 touchMonitor(cs); 100 101 //this.config=config; 102 } 103 104 105 public void touchMonitor(ConfigServerImpl cs) { 106 if(monitor!=null && monitor.isAlive()) return; 107 monitor = new Monitor(cs,controlerState); 108 monitor.setDaemon(true); 109 monitor.setPriority(Thread.MIN_PRIORITY); 110 monitor.start(); 111 } 112 113 /** 114 * get singelton instance of the CFML Engine 115 * @param factory 116 * @return CFMLEngine 117 */ 118 public static synchronized CFMLEngine getInstance(CFMLEngineFactory factory) { 119 if(engine==null) { 120 engine=new CFMLEngineImpl(factory); 121 122 } 123 return engine; 124 } 125 126 /** 127 * get singelton instance of the CFML Engine, throwsexception when not already init 128 * @param factory 129 * @return CFMLEngine 130 */ 131 public static synchronized CFMLEngine getInstance() throws ServletException { 132 if(engine!=null) return engine; 133 throw new ServletException("CFML Engine is not loaded"); 134 } 135 136 /** 137 * @see railo.loader.engine.CFMLEngine#addServletConfig(javax.servlet.ServletConfig) 138 */ 139 public void addServletConfig(ServletConfig config) throws ServletException { 140 String real=config.getServletContext().getRealPath("/"); 141 if(!initContextes.containsKey(real)) { 142 CFMLFactory jspFactory = loadJSPFactory(getConfigServerImpl(),config,initContextes.size()); 143 initContextes.put(real,jspFactory); 144 } 145 } 146 147 private ConfigServerImpl getConfigServerImpl() { 148 if(configServer==null) { 149 try { 150 ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); 151 152 Resource context = frp.getResource(factory.getResourceRoot().getAbsolutePath()).getRealResource("context"); 153 //CFMLEngineFactory.registerInstance(this);// patch, not really good but it works 154 configServer=ConfigServerFactory.newInstance( 155 this, 156 initContextes, 157 contextes, 158 context); 159 } catch (Exception e) { 160 e.printStackTrace(); 161 } 162 } 163 return configServer; 164 } 165 166 private CFMLFactoryImpl loadJSPFactory(ConfigServerImpl configServer, ServletConfig sg, int countExistingContextes) throws ServletException { 167 try { 168 // Load Config 169 Resource configDir=getConfigDirectory(sg,configServer,countExistingContextes); 170 171 QueryCacheSupport queryCache=QueryCacheSupport.getInstance(configServer); 172 CFMLFactoryImpl factory=new CFMLFactoryImpl(this,queryCache); 173 ConfigWebImpl config=ConfigWebFactory.newInstance(factory,configServer,configDir,sg); 174 queryCache.setConfigWeb(config); 175 factory.setConfig(config); 176 return factory; 177 } 178 catch (Exception e) { 179 ServletException se= new ServletException(e.getMessage()); 180 se.setStackTrace(e.getStackTrace()); 181 throw se; 182 } 183 184 } 185 186 /** 187 * loads Configuration File from System, from init Parameter from web.xml 188 * @param sg 189 * @param configServer 190 * @param countExistingContextes 191 * @return return path to directory 192 */ 193 private Resource getConfigDirectory(ServletConfig sg, ConfigServerImpl configServer, int countExistingContextes) throws PageServletException { 194 ServletContext sc=sg.getServletContext(); 195 String strConfig=sg.getInitParameter("configuration"); 196 if(strConfig==null)strConfig=sg.getInitParameter("railo-web-directory"); 197 if(strConfig==null)strConfig="{web-root-directory}/WEB-INF/railo/"; 198 else if("/WEB-INF/railo/".equals(strConfig))strConfig="{web-root-directory}/WEB-INF/railo/"; 199 200 // static path is not allowed 201 if(countExistingContextes>1 && strConfig!=null && strConfig.indexOf('{')==-1){ 202 String text="static path ["+strConfig+"] for servlet init param [railo-web-directory] is not allowed, path must use a web-context specific placeholder."; 203 System.err.println(text); 204 throw new PageServletException(new ApplicationException(text)); 205 } 206 strConfig=SystemUtil.parsePlaceHolder(strConfig,sc,configServer.getLabels()); 207 208 209 210 ResourceProvider frp = ResourcesImpl.getFileResourceProvider(); 211 Resource root = frp.getResource(sc.getRealPath("/")); 212 Resource configDir=ResourceUtil.createResource(root.getRealResource(strConfig), FileUtil.LEVEL_PARENT_FILE,FileUtil.TYPE_DIR); 213 214 if(configDir==null) { 215 configDir=ResourceUtil.createResource(frp.getResource(strConfig), FileUtil.LEVEL_GRAND_PARENT_FILE,FileUtil.TYPE_DIR); 216 } 217 if(configDir==null) throw new PageServletException(new ApplicationException("path ["+strConfig+"] is invalid")); 218 if(!configDir.exists()){ 219 try { 220 configDir.createDirectory(true); 221 } 222 catch (IOException e) {} 223 } 224 return configDir; 225 } 226 227 /** 228 * @see railo.loader.engine.CFMLEngine#getCFMLFactory(javax.servlet.ServletContext, javax.servlet.ServletConfig, javax.servlet.http.HttpServletRequest) 229 */ 230 231 public CFMLFactory getCFMLFactory(ServletContext srvContext, ServletConfig srvConfig,HttpServletRequest req) throws ServletException { 232 String real=srvContext.getRealPath("/"); 233 ConfigServerImpl cs = getConfigServerImpl(); 234 235 236 // Load JspFactory 237 CFMLFactoryImpl factory=null; 238 Object o=contextes.get(real); 239 if(o==null) { 240 //int size=sn.getContextCount(); 241 //if(size!=-1 && size <= contextes.size()) 242 //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()+"]"); 243 o=initContextes.get(real); 244 if(o!=null) { 245 factory=(CFMLFactoryImpl) o; 246 } 247 else { 248 factory=loadJSPFactory(cs,srvConfig,initContextes.size()); 249 initContextes.put(real,factory); 250 } 251 contextes.put(real,factory); 252 253 try { 254 String cp = req.getContextPath(); 255 if(cp==null)cp=""; 256 factory.setURL(new URL(req.getScheme(),req.getServerName(),req.getServerPort(),cp)); 257 } 258 catch (MalformedURLException e) { 259 e.printStackTrace(); 260 } 261 // 262 263 } 264 else { 265 factory=(CFMLFactoryImpl) o; 266 } 267 return factory; 268 } 269 270 /** 271 * @see railo.loader.engine.CFMLEngine#serviceCFML(javax.servlet.http.HttpServlet, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 272 */ 273 public void serviceCFML(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { 274 275 CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req); 276 PageContext pc = factory.getRailoPageContext(servlet,req,rsp,null,false,-1,false); 277 try { 278 /*print.out("INCLUDE"); 279 print.out("servlet_path:"+req.getAttribute("javax.servlet.include.servlet_path")); 280 print.out("request_uri:"+req.getAttribute("javax.servlet.include.request_uri")); 281 print.out("context_path:"+req.getAttribute("javax.servlet.include.context_path")); 282 print.out("path_info:"+req.getAttribute("javax.servlet.include.path_info")); 283 print.out("query_string:"+req.getAttribute("javax.servlet.include.query_string")); 284 print.out("FORWARD"); 285 print.out("servlet_path:"+req.getAttribute("javax.servlet.forward.servlet_path")); 286 print.out("request_uri:"+req.getAttribute("javax.servlet.forward.request_uri")); 287 print.out("context_path:"+req.getAttribute("javax.servlet.forward.context_path")); 288 print.out("path_info:"+req.getAttribute("javax.servlet.forward.path_info")); 289 print.out("query_string:"+req.getAttribute("javax.servlet.forward.query_string")); 290 print.out("---"); 291 print.out(req.getServletPath()); 292 print.out(pc.getHttpServletRequest().getServletPath()); 293 */ 294 295 296 297 pc.execute(pc.getHttpServletRequest().getServletPath(),false); 298 } 299 catch (PageException pe) { 300 throw new PageServletException(pe); 301 } 302 finally { 303 factory.releaseRailoPageContext(pc); 304 FDControllerFactory.notifyPageComplete(); 305 } 306 } 307 308 public void serviceFile(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { 309 req=new HTTPServletRequestWrap(req); 310 CFMLFactory factory=getCFMLFactory(servlet.getServletContext(), servlet.getServletConfig(), req); 311 ConfigWeb config = factory.getConfig(); 312 Resource res = ((ConfigWebImpl)config).getPhysicalResourceExisting(null, null, req.getServletPath(), false, true, true); 313 314 if(res==null) { 315 rsp.sendError(404); 316 } 317 else { 318 ReqRspUtil.setContentLength(rsp,res.length()); 319 String mt = servlet.getServletContext().getMimeType(req.getServletPath()); 320 if(!StringUtil.isEmpty(mt))rsp.setContentType(mt); 321 IOUtil.copy(res, rsp.getOutputStream(), true); 322 } 323 } 324 325 326 /*private String getContextList() { 327 return List.arrayToList((String[])contextes.keySet().toArray(new String[contextes.size()]),", "); 328 }*/ 329 330 /** 331 * @see railo.loader.engine.CFMLEngine#getVersion() 332 */ 333 public String getVersion() { 334 return Info.getVersionAsString(); 335 } 336 337 /** 338 * @see railo.loader.engine.CFMLEngine#getUpdateType() 339 */ 340 public String getUpdateType() { 341 return getConfigServerImpl().getUpdateType(); 342 } 343 344 /** 345 * @see railo.loader.engine.CFMLEngine#getUpdateLocation() 346 */ 347 public URL getUpdateLocation() { 348 return getConfigServerImpl().getUpdateLocation(); 349 } 350 351 /** 352 * @see railo.loader.engine.CFMLEngine#can(int, java.lang.String) 353 */ 354 public boolean can(int type, String password) { 355 return getConfigServerImpl().passwordEqual(password); 356 } 357 358 public CFMLEngineFactory getCFMLEngineFactory() { 359 return factory; 360 } 361 362 public void serviceAMF(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { 363 req=new HTTPServletRequestWrap(req); 364 amfEngine.service(servlet,req,rsp); 365 } 366 367 /** 368 * @see railo.loader.engine.CFMLEngine#reset() 369 */ 370 public void reset() { 371 reset(null); 372 } 373 374 /** 375 * @see railo.loader.engine.CFMLEngine#reset(String) 376 */ 377 public void reset(String configId) { 378 379 CFMLFactoryImpl cfmlFactory; 380 //ScopeContext scopeContext; 381 try { 382 Iterator it = contextes.keySet().iterator(); 383 while(it.hasNext()) { 384 try { 385 cfmlFactory=(CFMLFactoryImpl)contextes.get(it.next()); 386 if(configId!=null && !configId.equals(cfmlFactory.getConfigWebImpl().getId())) continue; 387 388 // scopes 389 try{cfmlFactory.getScopeContext().clear();}catch(Throwable t){t.printStackTrace();} 390 391 // PageContext 392 try{cfmlFactory.resetPageContext();}catch(Throwable t){t.printStackTrace();} 393 394 // Query Cache 395 try{ cfmlFactory.getQueryCache().clear();}catch(Throwable t){t.printStackTrace();} 396 397 // Gateway 398 try{ cfmlFactory.getConfigWebImpl().getGatewayEngine().reset();}catch(Throwable t){t.printStackTrace();} 399 400 } 401 catch(Throwable t){ 402 t.printStackTrace(); 403 } 404 } 405 } 406 finally { 407 // Controller 408 controlerState.setValue(false); 409 } 410 } 411 412 /** 413 * @see railo.loader.engine.CFMLEngine#getCastUtil() 414 */ 415 public Cast getCastUtil() { 416 return CastImpl.getInstance(); 417 } 418 419 /** 420 * @see railo.loader.engine.CFMLEngine#getOperatonUtil() 421 */ 422 public Operation getOperatonUtil() { 423 return OperationImpl.getInstance(); 424 } 425 426 /** 427 * @see railo.loader.engine.CFMLEngine#getDecisionUtil() 428 */ 429 public Decision getDecisionUtil() { 430 return DecisionImpl.getInstance(); 431 } 432 433 /** 434 * @see railo.loader.engine.CFMLEngine#getExceptionUtil() 435 */ 436 public Excepton getExceptionUtil() { 437 return ExceptonImpl.getInstance(); 438 } 439 440 /** 441 * @see railo.loader.engine.CFMLEngine#getCreationUtil() 442 */ 443 public Creation getCreationUtil() { 444 return CreationImpl.getInstance(); 445 } 446 447 /** 448 * @see railo.loader.engine.CFMLEngine#getBlazeDSUtil() 449 */ 450 public Object getBlazeDSUtil() { 451 return new BlazeDSImpl(); 452 } 453 454 /** 455 * @see railo.loader.engine.CFMLEngine#getFDController() 456 */ 457 public Object getFDController() { 458 engine.allowRequestTimeout(false); 459 460 return new FDControllerImpl(engine,engine.getConfigServerImpl().getSerialNumber()); 461 } 462 463 public Map getCFMLFactories() { 464 return initContextes; 465 } 466 467 /** 468 * @see railo.loader.engine.CFMLEngine#getResourceUtil() 469 */ 470 public railo.runtime.util.ResourceUtil getResourceUtil() { 471 return ResourceUtilImpl.getInstance(); 472 } 473 474 /** 475 * @see railo.loader.engine.CFMLEngine#getHTTPUtil() 476 */ 477 public HTTPUtil getHTTPUtil() { 478 return HTTPUtilImpl.getInstance(); 479 } 480 481 /** 482 * @see railo.loader.engine.CFMLEngine#getThreadPageContext() 483 */ 484 public PageContext getThreadPageContext() { 485 return ThreadLocalPageContext.get(); 486 } 487 488 /** 489 * @see railo.loader.engine.CFMLEngine#getVideoUtil() 490 */ 491 public VideoUtil getVideoUtil() { 492 return VideoUtilImpl.getInstance(); 493 } 494 495 /** 496 * @see railo.loader.engine.CFMLEngine#getZipUtil() 497 */ 498 public ZipUtil getZipUtil() { 499 return ZipUtilImpl.getInstance(); 500 } 501 502 /** 503 * @see railo.loader.engine.CFMLEngine#getState() 504 */ 505 public String getState() { 506 return Info.getStateAsString(); 507 } 508 509 public void allowRequestTimeout(boolean allowRequestTimeout) { 510 this.allowRequestTimeout=allowRequestTimeout; 511 } 512 513 public boolean allowRequestTimeout() { 514 return allowRequestTimeout; 515 } 516 517 public boolean isRunning() { 518 try{ 519 CFMLEngine other = CFMLEngineFactory.getInstance(); 520 // FUTURE patch, do better impl when changing loader 521 if(other!=this && controlerState.toBooleanValue() && !(other instanceof CFMLEngineWrapper)) { 522 SystemOut.printDate("CFMLEngine is still set to true but no longer valid, Railo disable this CFMLEngine."); 523 controlerState.setValue(false); 524 reset(); 525 return false; 526 } 527 } 528 catch(Throwable t){} 529 return controlerState.toBooleanValue(); 530 } 531 532 }