001 package railo.runtime.listener; 002 003 import java.io.IOException; 004 import java.io.OutputStream; 005 import java.util.HashMap; 006 import java.util.Map; 007 008 import javax.servlet.http.Cookie; 009 010 import railo.commons.io.DevNullOutputStream; 011 import railo.commons.io.res.Resource; 012 import railo.commons.io.res.util.ResourceUtil; 013 import railo.commons.lang.StringUtil; 014 import railo.commons.lang.types.RefBoolean; 015 import railo.commons.lang.types.RefBooleanImpl; 016 import railo.runtime.CFMLFactory; 017 import railo.runtime.Component; 018 import railo.runtime.ComponentPage; 019 import railo.runtime.ComponentPro; 020 import railo.runtime.PageContext; 021 import railo.runtime.PageContextImpl; 022 import railo.runtime.PageSource; 023 import railo.runtime.component.ComponentLoader; 024 import railo.runtime.component.Member; 025 import railo.runtime.exp.Abort; 026 import railo.runtime.exp.MissingIncludeException; 027 import railo.runtime.exp.PageException; 028 import railo.runtime.interpreter.JSONExpressionInterpreter; 029 import railo.runtime.net.http.HttpServletRequestDummy; 030 import railo.runtime.net.http.HttpServletResponseDummy; 031 import railo.runtime.op.Caster; 032 import railo.runtime.op.Decision; 033 import railo.runtime.orm.ORMUtil; 034 import railo.runtime.type.Array; 035 import railo.runtime.type.ArrayImpl; 036 import railo.runtime.type.Collection; 037 import railo.runtime.type.Collection.Key; 038 import railo.runtime.type.KeyImpl; 039 import railo.runtime.type.Struct; 040 import railo.runtime.type.cfc.ComponentAccess; 041 import railo.runtime.type.util.ArrayUtil; 042 import railo.runtime.type.util.StructUtil; 043 044 public class ModernAppListener extends AppListenerSupport { 045 046 047 048 049 050 private static final Collection.Key ON_REQUEST_START = KeyImpl.intern("onRequestStart"); 051 private static final Collection.Key ON_CFCREQUEST = KeyImpl.intern("onCFCRequest"); 052 private static final Collection.Key ON_REQUEST = KeyImpl.intern("onRequest"); 053 private static final Collection.Key ON_REQUEST_END = KeyImpl.intern("onRequestEnd"); 054 private static final Collection.Key ON_APPLICATION_START = KeyImpl.intern("onApplicationStart"); 055 private static final Collection.Key ON_APPLICATION_END = KeyImpl.intern("onApplicationEnd"); 056 private static final Collection.Key ON_SESSION_START = KeyImpl.intern("onSessionStart"); 057 private static final Collection.Key ON_SESSION_END = KeyImpl.intern("onSessionEnd"); 058 private static final Collection.Key ON_DEBUG = KeyImpl.intern("onDebug"); 059 private static final Collection.Key ON_ERROR = KeyImpl.intern("onError"); 060 private static final Collection.Key ON_MISSING_TEMPLATE = KeyImpl.intern("onMissingTemplate"); 061 062 063 //private ComponentImpl app; 064 private Map apps=new HashMap(); 065 protected int mode=MODE_CURRENT2ROOT; 066 private String type; 067 private Boolean hasOnSessionStart; 068 069 //private ApplicationContextImpl appContext; 070 //private long cfcCompileTime; 071 072 073 /** 074 * 075 * @throws PageException 076 * @see railo.runtime.listener.ApplicationListener#onRequest(railo.runtime.PageContext, railo.runtime.PageSource) 077 */ 078 public void onRequest(PageContext pc, PageSource requestedPage) throws PageException { 079 // on requestStart 080 PageSource appPS=//pc.isCFCRequest()?null: 081 AppListenerUtil.getApplicationPageSource(pc,requestedPage,"Application.cfc",mode); 082 083 _onRequest(pc, requestedPage, appPS); 084 } 085 086 protected void _onRequest(PageContext pc, PageSource requestedPage,PageSource appPS) throws PageException { 087 PageContextImpl pci = (PageContextImpl)pc; 088 if(appPS!=null) { 089 String callPath=appPS.getComponentName(); 090 091 092 ComponentAccess app = ComponentLoader.loadComponent(pci,null,appPS, callPath, false,false); 093 094 String targetPage=requestedPage.getFullRealpath(); 095 // init 096 initApplicationContext(pci,app); 097 098 099 apps.put(pc.getApplicationContext().getName(), app); 100 101 if(!pci.initApplicationContext()) return; 102 103 104 // onRequestStart 105 if(app.contains(pc,ON_REQUEST_START)) { 106 Object rtn=call(app,pci, ON_REQUEST_START, new Object[]{targetPage}); 107 if(!Caster.toBooleanValue(rtn,true)) 108 return; 109 } 110 111 // onRequest 112 boolean isCFC=ResourceUtil.getExtension(targetPage,"").equalsIgnoreCase(pc.getConfig().getCFCExtension()); 113 Object method; 114 if(isCFC && app.contains(pc,ON_CFCREQUEST) && (method=pc.urlFormScope().get(ComponentPage.METHOD,null))!=null) { 115 116 Struct url = StructUtil.duplicate(pc.urlFormScope(),true); 117 118 url.removeEL(KeyImpl.FIELD_NAMES); 119 url.removeEL(ComponentPage.METHOD); 120 Object args=url.get(KeyImpl.ARGUMENT_COLLECTION,null); 121 Object returnFormat=url.removeEL(KeyImpl.RETURN_FORMAT); 122 Object queryFormat=url.removeEL(ComponentPage.QUERY_FORMAT); 123 124 if(args==null){ 125 args=pc.getHttpServletRequest().getAttribute("argumentCollection"); 126 } 127 128 if(args instanceof String){ 129 args=new JSONExpressionInterpreter().interpret(pc, (String)args); 130 } 131 132 if(args!=null) { 133 if(Decision.isCastableToStruct(args)){ 134 Struct sct = Caster.toStruct(args,false); 135 Key[] keys = url.keys(); 136 for(int i=0;i<keys.length;i++){ 137 sct.setEL(keys[i],url.get(keys[i])); 138 } 139 args=sct; 140 } 141 else if(Decision.isCastableToArray(args)){ 142 args = Caster.toArray(args); 143 } 144 else { 145 Array arr = new ArrayImpl(); 146 arr.appendEL(args); 147 args=arr; 148 } 149 } 150 else 151 args=url; 152 153 //print.out("c:"+requestedPage.getComponentName()); 154 //print.out("c:"+requestedPage.getComponentName()); 155 Object rtn = call(app,pci, ON_CFCREQUEST, new Object[]{requestedPage.getComponentName(),method,args}); 156 157 if(rtn!=null){ 158 if(pc.getHttpServletRequest().getHeader("AMF-Forward")!=null) { 159 pc.variablesScope().setEL("AMF-Forward", rtn); 160 //ThreadLocalWDDXResult.set(rtn); 161 } 162 else { 163 try { 164 pc.forceWrite(ComponentPage.convertResult(pc,app,method.toString(),returnFormat,queryFormat,rtn)); 165 } catch (Exception e) { 166 throw Caster.toPageException(e); 167 } 168 } 169 } 170 171 172 } 173 else if(!isCFC && app.contains(pc,ON_REQUEST)) { 174 call(app,pci, ON_REQUEST, new Object[]{targetPage}); 175 } 176 else { 177 // TODO impl die nicht so generisch ist 178 try{ 179 pci.doInclude(requestedPage); 180 } 181 catch(PageException pe){ 182 if(!Abort.isSilentAbort(pe)) { 183 if(pe instanceof MissingIncludeException){ 184 if(((MissingIncludeException) pe).getPageSource().equals(requestedPage)){ 185 if(app.contains(pc,ON_MISSING_TEMPLATE)) { 186 if(!Caster.toBooleanValue(call(app,pci, ON_MISSING_TEMPLATE, new Object[]{targetPage}),true)) 187 throw pe; 188 } 189 else throw pe; 190 } 191 else throw pe; 192 } 193 else throw pe; 194 } 195 } 196 } 197 198 // onRequestEnd 199 if(app.contains(pc,ON_REQUEST_END)) { 200 call(app,pci, ON_REQUEST_END, new Object[]{targetPage}); 201 } 202 } 203 else { 204 apps.put(pc.getApplicationContext().getName(), null); 205 pc.doInclude(requestedPage); 206 } 207 } 208 209 210 /** 211 * 212 * @see railo.runtime.listener.ApplicationListener#onApplicationStart(railo.runtime.PageContext) 213 */ 214 public boolean onApplicationStart(PageContext pc) throws PageException { 215 ComponentAccess app = (ComponentAccess) apps.get(pc.getApplicationContext().getName()); 216 if(app!=null && app.contains(pc,ON_APPLICATION_START)) { 217 Object rtn = call(app,pc, ON_APPLICATION_START, ArrayUtil.OBJECT_EMPTY); 218 return Caster.toBooleanValue(rtn,true); 219 } 220 return true; 221 } 222 223 public void onApplicationEnd(CFMLFactory factory, String applicationName) throws PageException { 224 ComponentAccess app = (ComponentAccess) apps.get(applicationName); 225 if(app==null || !app.containsKey(ON_APPLICATION_END)) return; 226 227 PageContextImpl pc=null; 228 try { 229 pc = (PageContextImpl) createPageContext(factory,app,applicationName,null,ON_APPLICATION_END); 230 call(app,pc, ON_APPLICATION_END, new Object[]{pc.applicationScope()}); 231 } 232 finally { 233 if(pc!=null){ 234 factory.releasePageContext(pc); 235 } 236 } 237 } 238 239 /** 240 * 241 * @see railo.runtime.listener.ApplicationListener#onSessionStart(railo.runtime.PageContext) 242 */ 243 public void onSessionStart(PageContext pc) throws PageException { 244 ComponentAccess app = (ComponentAccess) apps.get(pc.getApplicationContext().getName()); 245 if(hasOnSessionStart(pc,app)) { 246 call(app,pc, ON_SESSION_START, ArrayUtil.OBJECT_EMPTY); 247 } 248 } 249 250 /** 251 * 252 * @see railo.runtime.listener.ApplicationListener#onSessionEnd(railo.runtime.CFMLFactory, java.lang.String, java.lang.String) 253 */ 254 public void onSessionEnd(CFMLFactory factory, String applicationName, String cfid) throws PageException { 255 ComponentAccess app = (ComponentAccess) apps.get(applicationName); 256 if(app==null || !app.containsKey(ON_SESSION_END)) return; 257 258 PageContextImpl pc=null; 259 try { 260 pc = createPageContext(factory,app,applicationName,cfid,ON_SESSION_END); 261 call(app,pc, ON_SESSION_END, new Object[]{pc.sessionScope(false),pc.applicationScope()}); 262 } 263 finally { 264 if(pc!=null){ 265 factory.releasePageContext(pc); 266 } 267 } 268 } 269 270 private PageContextImpl createPageContext(CFMLFactory factory, ComponentAccess app, String applicationName, String cfid,Collection.Key methodName) throws PageException { 271 Resource root = factory.getConfig().getRootDirectory(); 272 String path = app.getPageSource().getFullRealpath(); 273 274 // Request 275 HttpServletRequestDummy req = new HttpServletRequestDummy(root,"localhost",path,"",null,null,null,null,null); 276 if(!StringUtil.isEmpty(cfid))req.setCookies(new Cookie[]{new Cookie("cfid",cfid),new Cookie("cftoken","0")}); 277 278 // Response 279 OutputStream os=DevNullOutputStream.DEV_NULL_OUTPUT_STREAM; 280 try { 281 Resource out = factory.getConfig().getConfigDir().getRealResource("output/"+methodName.getString()+".out"); 282 out.getParentResource().mkdirs(); 283 os = out.getOutputStream(false); 284 } 285 catch (IOException e) { 286 e.printStackTrace(); 287 // TODO was passiert hier 288 } 289 HttpServletResponseDummy rsp = new HttpServletResponseDummy(os); 290 291 // PageContext 292 PageContextImpl pc = (PageContextImpl) factory.getRailoPageContext(factory.getServlet(), req, rsp, null, false, -1, false); 293 // ApplicationContext 294 ClassicApplicationContext ap = new ClassicApplicationContext(factory.getConfig(),applicationName,false,app==null?null:ResourceUtil.getResource(pc,app.getPageSource(),null)); 295 initApplicationContext(pc, app); 296 ap.setName(applicationName); 297 ap.setSetSessionManagement(true); 298 //if(!ap.hasName())ap.setName("Controler") 299 // Base 300 pc.setBase(app.getPageSource()); 301 302 return pc; 303 } 304 305 /** 306 * 307 * @see railo.runtime.listener.ApplicationListener#onDebug(railo.runtime.PageContext) 308 */ 309 public void onDebug(PageContext pc) throws PageException { 310 if(((PageContextImpl)pc).isGatewayContext()) return; 311 ComponentAccess app = (ComponentAccess) apps.get(pc.getApplicationContext().getName()); 312 if(app!=null && app.contains(pc,ON_DEBUG)) { 313 call(app,pc, ON_DEBUG, new Object[]{pc.getDebugger().getDebuggingData()}); 314 return; 315 } 316 try { 317 pc.getDebugger().writeOut(pc); 318 } 319 catch (IOException e) { 320 throw Caster.toPageException(e); 321 } 322 } 323 324 /** 325 * 326 * @see railo.runtime.listener.ApplicationListener#onError(railo.runtime.PageContext, railo.runtime.exp.PageException) 327 */ 328 public void onError(PageContext pc, PageException pe) { 329 ComponentAccess app = (ComponentAccess) apps.get(pc.getApplicationContext().getName()); 330 if(app!=null && app.containsKey(ON_ERROR) && !Abort.isSilentAbort(pe)) { 331 try { 332 String eventName=""; 333 if(pe instanceof ModernAppListenerException) eventName= ((ModernAppListenerException)pe).getEventName(); 334 if(eventName==null)eventName=""; 335 336 call(app,pc, ON_ERROR, new Object[]{pe.getCatchBlock(pc),eventName}); 337 return; 338 } 339 catch(PageException _pe) { 340 pe=_pe; 341 } 342 } 343 pc.handlePageException(pe); 344 } 345 346 347 private Object call(ComponentPro app, PageContext pc, Collection.Key eventName, Object[] args) throws ModernAppListenerException { 348 try { 349 return app.call(pc, eventName, args); 350 } 351 catch (PageException pe) { 352 if(Abort.isSilentAbort(pe)) return Boolean.FALSE; 353 throw new ModernAppListenerException(pe,eventName.getString()); 354 } 355 } 356 357 private void initApplicationContext(PageContextImpl pc, ComponentAccess app) throws PageException { 358 359 // use existing app context 360 RefBoolean throwsErrorWhileInit=new RefBooleanImpl(false); 361 ModernApplicationContext appContext = new ModernApplicationContext(pc,app,throwsErrorWhileInit); 362 363 364 pc.setApplicationContext(appContext); 365 if(appContext.isORMEnabled()) { 366 boolean hasError=throwsErrorWhileInit.toBooleanValue(); 367 if(hasError)pc.addPageSource(app.getPageSource(), true); 368 try{ 369 ORMUtil.resetEngine(pc,false); 370 } 371 finally { 372 if(hasError)pc.removeLastPageSource(true); 373 } 374 } 375 } 376 377 378 private static Object get(ComponentAccess app, Key name,String defaultValue) { 379 Member mem = app.getMember(Component.ACCESS_PRIVATE, name, true, false); 380 if(mem==null) return defaultValue; 381 return mem.getValue(); 382 } 383 384 /** 385 * 386 * @see railo.runtime.listener.ApplicationListener#setMode(int) 387 */ 388 public void setMode(int mode) { 389 this.mode=mode; 390 } 391 392 /** 393 * 394 * @see railo.runtime.listener.ApplicationListener#getMode() 395 */ 396 public int getMode() { 397 return mode; 398 } 399 400 401 /** 402 * @return the type 403 */ 404 public String getType() { 405 return type; 406 } 407 408 /** 409 * @param type the type to set 410 */ 411 public void setType(String type) { 412 this.type = type; 413 } 414 415 /** 416 * @see railo.runtime.listener.AppListenerSupport#hasOnSessionStart(railo.runtime.PageContext) 417 */ 418 public boolean hasOnSessionStart(PageContext pc) { 419 return hasOnSessionStart(pc,(ComponentAccess) apps.get(pc.getApplicationContext().getName())); 420 } 421 private boolean hasOnSessionStart(PageContext pc,ComponentAccess app) { 422 return app!=null && app.contains(pc,ON_SESSION_START); 423 } 424 }