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