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    }