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