001    package railo.runtime.engine;
002    
003    import java.io.ByteArrayOutputStream;
004    import java.io.DataInputStream;
005    import java.io.DataOutputStream;
006    import java.io.IOException;
007    import java.util.Iterator;
008    
009    import javax.servlet.ServletException;
010    import javax.servlet.ServletOutputStream;
011    import javax.servlet.http.HttpServlet;
012    import javax.servlet.http.HttpServletRequest;
013    import javax.servlet.http.HttpServletResponse;
014    
015    import org.openamf.AMFBody;
016    import org.openamf.AMFError;
017    import org.openamf.AMFMessage;
018    import org.openamf.ServiceRequest;
019    import org.openamf.io.AMFDeserializer;
020    import org.openamf.io.AMFSerializer;
021    
022    import railo.commons.io.IOUtil;
023    import railo.runtime.exp.PageException;
024    import railo.runtime.net.amf.CFMLProxy;
025    import railo.runtime.net.amf.OpenAMFCaster;
026    
027    
028    /**
029     * AMF Engine
030     */
031    public final class AMFEngine {
032        
033    
034    
035        /**
036         * Main entry point for the servlet
037         * @param servlet 
038         * @param req 
039         * @param rsp 
040         *
041         * @throws ServletException
042         * @throws IOException
043         */
044        public void service(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp) throws IOException {
045            
046            AMFMessage requestMessage = null;
047            AMFMessage responseMessage = null;
048            requestMessage = deserializeAMFMessage(req);
049            responseMessage = processMessage(servlet, req, rsp, requestMessage);
050            serializeAMFMessage(rsp, responseMessage);
051        }
052    
053        /**
054         * Uses the AMFDeserializer to deserialize the request
055         * 
056         * @see org.openamf.io.AMFDeserializer
057         */
058        private AMFMessage deserializeAMFMessage(HttpServletRequest req) throws IOException {
059            DataInputStream dis = null;
060            try {
061                    dis = new DataInputStream(req.getInputStream());
062                    AMFDeserializer deserializer = new AMFDeserializer(dis);
063                    AMFMessage message = deserializer.getAMFMessage();
064                    return message;
065            }
066            finally {
067                    IOUtil.closeEL(dis);
068            }
069        }
070    
071        /**
072         * Uses the AMFSerializer to serialize the request
073         *
074         * @see org.openamf.io.AMFSerializer
075         */
076        private void serializeAMFMessage(HttpServletResponse resp, AMFMessage message) throws IOException {
077            ByteArrayOutputStream baos = new ByteArrayOutputStream();
078            DataOutputStream dos = new DataOutputStream(baos);
079            AMFSerializer serializer = new AMFSerializer(dos);
080            serializer.serializeMessage(message);
081            resp.setContentType("application/x-amf");
082            resp.setContentLength(baos.size());
083            ServletOutputStream sos = resp.getOutputStream(); 
084            baos.writeTo(sos);
085            sos.flush();
086        }
087    
088        /**
089         * Iterates through the request message's bodies, invokes each body and
090         * then, builds a message to send as the results
091         * @param req 
092         * @param rsp 
093         * @param message 
094         * @return AMFMessage
095         * @throws IOException 
096         * @throws ServletException 
097         */
098        private AMFMessage processMessage(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp, AMFMessage message)  {
099            AMFMessage responseMessage = new AMFMessage();
100            for (Iterator bodies = message.getBodies(); bodies.hasNext();) {
101                AMFBody requestBody = (AMFBody) bodies.next();
102                // invoke
103                Object serviceResult = invokeBody(servlet,req, rsp, requestBody);
104                String target = getTarget(requestBody, serviceResult);
105                AMFBody responseBody = new AMFBody(target, "null", serviceResult);
106                responseMessage.addBody(responseBody);
107            }
108            return responseMessage;
109        }
110    
111        
112        private Object invokeBody(HttpServlet servlet, HttpServletRequest req, HttpServletResponse rsp, AMFBody requestBody) { 
113            try {
114                    ServiceRequest request = new ServiceRequest(requestBody);
115                    rsp.getOutputStream();// MUST muss das sein?
116                   
117                    return new CFMLProxy().invokeBody(OpenAMFCaster.getInstance(),null,servlet.getServletContext(),servlet.getServletConfig(), req, rsp, request.getServiceName(), request.getServiceMethodName(), request.getParameters());
118                    } 
119            catch (Exception e) {
120                    e.printStackTrace();
121                rsp.setStatus(200);
122                AMFError error=new AMFError();
123                e.setStackTrace(e.getStackTrace());
124                error.setDescription(e.getMessage());
125                            
126                            if(e instanceof PageException){
127                                    PageException pe = (PageException)e;
128                        error.setCode(pe.getErrorCode());
129                        error.setCode(pe.getErrorCode());
130                        error.setDetails(pe.getDetail());
131                            }
132                            
133                            return error;
134                    } 
135        }
136    
137        private String getTarget(AMFBody requestBody, Object serviceResult) {
138            String target = "/onResult";
139            if (serviceResult instanceof AMFError) {
140                target = "/onStatus";
141            }
142            return requestBody.getResponse() + target;
143        }
144    }