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    }