001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.net.amf;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.OutputStream;
024import java.util.ArrayList;
025import java.util.List;
026import java.util.Map;
027
028import javax.servlet.ServletConfig;
029import javax.servlet.ServletContext;
030import javax.servlet.ServletException;
031import javax.servlet.http.Cookie;
032import javax.servlet.http.HttpServletRequest;
033import javax.servlet.http.HttpServletResponse;
034
035import lucee.commons.io.DevNullOutputStream;
036import lucee.commons.io.res.Resource;
037import lucee.commons.lang.Pair;
038import lucee.commons.lang.SystemOut;
039import lucee.runtime.CFMLFactory;
040import lucee.runtime.PageContext;
041import lucee.runtime.PageContextImpl;
042import lucee.runtime.PageSource;
043import lucee.runtime.config.ConfigImpl;
044import lucee.runtime.config.ConfigWebImpl;
045import lucee.runtime.engine.CFMLEngineImpl;
046import lucee.runtime.exp.PageException;
047import lucee.runtime.net.http.HttpServletRequestDummy;
048import lucee.runtime.net.http.HttpServletResponseDummy;
049import lucee.runtime.net.http.HttpUtil;
050import lucee.runtime.net.http.ReqRspUtil;
051import lucee.runtime.op.Caster;
052import lucee.runtime.type.Collection;
053import lucee.runtime.type.KeyImpl;
054import lucee.runtime.type.Struct;
055import lucee.runtime.type.StructImpl;
056import flex.messaging.config.ConfigMap;
057
058public class CFMLProxy {
059
060        private static final Collection.Key FLASH = KeyImpl.intern("flash");
061        private static final Collection.Key PARAMS = KeyImpl.intern("params");
062        private static final Collection.Key RESULT = KeyImpl.intern("result");
063        private static final Collection.Key AMF_FORWARD = KeyImpl.intern("AMF-Forward");
064        
065        
066
067        public Object invokeBody(AMFCaster caster,ConfigMap configMap,ServletContext context,ServletConfig config,HttpServletRequest req, 
068                        HttpServletResponse rsp,String serviceName,String serviceMethodName,List rawParams) throws ServletException, PageException,IOException { 
069    
070                //try { 
071        
072        
073        // Forward
074        CFMLFactory factory = CFMLEngineImpl.getInstance().getCFMLFactory(context, config, req);
075        PageContext pc=null;
076
077        // CFC Files
078        String cfc;
079        Object parameters=null;
080        try {
081            cfc="/"+serviceName.replace('.','/')+".cfc";
082            ByteArrayOutputStream baos = new ByteArrayOutputStream();
083            pc=createPageContext(factory,cfc,"method="+serviceMethodName,baos,req);
084            PageSource source = ((PageContextImpl)pc).getPageSourceExisting(cfc);
085
086            if(caster==null)caster=((ConfigImpl)pc.getConfig()).getAMFCaster(configMap);
087            parameters=caster.toCFMLObject(rawParams);
088                if(source!=null) {
089                        print(pc,cfc+"?method="+serviceMethodName);
090                // Map
091                                //print.err(parameters);
092                        if(parameters instanceof Map){
093                                //print.err("map");
094                        pc.getHttpServletRequest().setAttribute("argumentCollection", parameters);
095                }
096                        // List
097                else if(parameters instanceof List){
098                        //print.err("list");
099                        pc.getHttpServletRequest().setAttribute("argumentCollection", parameters);
100                }
101                else {
102                        ArrayList list = new ArrayList();
103                        list.add(parameters);
104                        pc.getHttpServletRequest().setAttribute("argumentCollection", list);
105                        
106                }
107                
108                // Execute
109                pc.execute(cfc,true);
110
111                // write back response
112                writeBackResponse(pc,rsp);
113                
114                // After
115                    return caster.toAMFObject(pc.variablesScope().get(AMF_FORWARD,null));
116                    
117            }
118        }
119        finally {
120            if(pc!=null)factory.releaseLuceePageContext(pc);
121        }    
122        
123     // CFML Files
124        String cfml;
125        try {
126            cfml="/"+(serviceName.replace('.','/')+'/'+serviceMethodName.replace('.','/'))+".cfm";
127            pc=createPageContext(factory,cfml,"",null,req);
128            PageSource source = ((PageContextImpl)pc).getPageSourceExisting(cfml);
129            
130            if(source!=null) {
131                print(pc,cfml);
132                // Before
133                Struct params=new StructImpl();
134                pc.variablesScope().setEL(FLASH,params);
135                params.setEL(PARAMS,parameters);
136                
137                // Execute
138                pc.execute(cfml,true);
139                
140                // write back response
141                writeBackResponse(pc,rsp);
142                
143                // After
144                Object flash=pc.variablesScope().get(FLASH,null);
145                if(flash instanceof Struct) {
146                        return caster.toAMFObject(((Struct)flash).get(RESULT,null));
147                }
148                return null;
149            }
150        }
151        finally {
152            if(pc!=null)factory.releaseLuceePageContext(pc);
153        }
154        
155        throw new AMFException("can't find cfml ("+cfml+") or cfc ("+cfc+") matching the request");
156    }
157        
158        private PageContext createPageContext(CFMLFactory factory,String scriptName,String queryString, OutputStream os, HttpServletRequest formerReq) {
159                Resource root = factory.getConfig().getRootDirectory();
160                if(os==null)os=DevNullOutputStream.DEV_NULL_OUTPUT_STREAM;
161                
162                // Request
163                HttpServletRequestDummy req = new HttpServletRequestDummy(
164                                root,"localhost",scriptName,queryString,
165                                ReqRspUtil.getCookies(formerReq,((ConfigImpl)factory.getConfig())._getWebCharset()),
166                                HttpUtil.cloneHeaders(formerReq),
167                                HttpUtil.cloneParameters(formerReq),
168                                HttpUtil.getAttributesAsStruct(formerReq),null);
169                                req.addHeader("AMF-Forward", "true");
170                HttpServletResponseDummy rsp = new HttpServletResponseDummy(os);
171
172                return  factory.getLuceePageContext(factory.getServlet(), req, rsp, null, false, -1, false);
173        }
174        
175        private void writeBackResponse(PageContext pc, HttpServletResponse rsp) {
176                HttpServletResponseDummy hsrd=(HttpServletResponseDummy) pc.getHttpServletResponse();
177        
178                // Cookie
179                Cookie[] cookies = hsrd.getCookies();
180        if(cookies!=null) {
181                for(int i=0;i<cookies.length;i++) {
182                        rsp.addCookie(cookies[i]);
183                }
184        }
185        
186        // header
187        Pair<String,Object>[] headers = hsrd.getHeaders();
188        Pair<String,Object> header ;
189        Object value;
190        if(headers!=null) {
191                for(int i=0;i<headers.length;i++) {
192                        header=headers[i];
193                        value=header.getValue();
194                        if(value instanceof Long)rsp.addDateHeader(header.getName(), ((Long)value).longValue());
195                        else if(value instanceof Integer)rsp.addDateHeader(header.getName(), ((Integer)value).intValue());
196                        else rsp.addHeader(header.getName(), Caster.toString(header.getValue(),""));
197                }
198        }
199        }
200        
201        private void print(PageContext pc, String str) {
202                if(pc.getConfig() instanceof ConfigWebImpl)
203                        SystemOut.printDate(((ConfigWebImpl)pc.getConfig()).getOutWriter(), str);
204        
205        }
206}