001/**
002 *   GRANITE DATA SERVICES
003 *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 *   This file is part of the Granite Data Services Platform.
006 *
007 *   Granite Data Services is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2.1 of the License, or (at your option) any later version.
011 *
012 *   Granite Data Services is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 *   General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public
018 *   License along with this library; if not, write to the Free Software
019 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 *   USA, or see <http://www.gnu.org/licenses/>.
021 */
022package org.granite.messaging.webapp;
023
024import java.io.BufferedInputStream;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.OutputStream;
028
029import javax.servlet.ServletContext;
030import javax.servlet.ServletException;
031import javax.servlet.http.HttpServletRequest;
032import javax.servlet.http.HttpServletResponse;
033
034import org.granite.config.GraniteConfig;
035import org.granite.config.GraniteConfigListener;
036import org.granite.config.flex.ServicesConfig;
037import org.granite.context.GraniteContext;
038import org.granite.logging.Logger;
039import org.granite.messaging.amf.AMF0Message;
040import org.granite.messaging.amf.io.AMF0Deserializer;
041import org.granite.messaging.amf.io.AMF0Serializer;
042import org.granite.messaging.amf.process.AMF0MessageProcessor;
043import org.granite.messaging.jmf.JMFDeserializer;
044import org.granite.messaging.jmf.JMFSerializer;
045import org.granite.messaging.jmf.SharedContext;
046import org.granite.util.ContentType;
047
048/**
049 * @author Franck WOLFF
050 */
051public class AMFEndpoint {
052
053    private static final Logger log = Logger.getLogger(AMFEndpoint.class);
054    
055    public void init(ServletContext context) {
056    }
057    
058    public void destroy() {
059    }
060    
061    public void service(GraniteConfig graniteConfig, ServicesConfig servicesConfig, ServletContext context,
062                HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
063        
064        if (ContentType.JMF_AMF.mimeType().equals(request.getContentType()))
065                serviceJMFAMF(graniteConfig, servicesConfig, context, request, response);
066        else
067                serviceAMF(graniteConfig, servicesConfig, context, request, response);
068    }
069    
070    protected void serviceAMF(GraniteConfig graniteConfig, ServicesConfig servicesConfig, ServletContext context,
071                HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {            
072            log.debug(">> Incoming AMF0 request from: %s", request.getRequestURL());
073
074            InputStream is = null;
075            OutputStream os = null;
076            
077            try {
078                is = new BufferedInputStream(request.getInputStream());
079                
080                HttpGraniteContext.createThreadIntance(
081                    graniteConfig, servicesConfig, context,
082                    request, response
083                );
084        
085                log.debug(">> Deserializing AMF0 request...");
086        
087                AMF0Deserializer deserializer = new AMF0Deserializer(is);
088                AMF0Message amf0Request = deserializer.getAMFMessage();
089
090            log.debug(">> Processing AMF0 request: %s", amf0Request);
091
092            AMF0Message amf0Response = AMF0MessageProcessor.process(amf0Request);
093        
094                log.debug("<< Serializing AMF0 response: %s", amf0Response);
095        
096                response.setStatus(HttpServletResponse.SC_OK);
097                response.setContentType(ContentType.AMF.mimeType());
098                response.setDateHeader("Expire", 0L);
099                response.setHeader("Cache-Control", "no-store");
100                
101                os = response.getOutputStream();
102                AMF0Serializer serializer = new AMF0Serializer(os);
103                
104                serializer.serializeMessage(amf0Response);
105                
106                response.flushBuffer();
107            }
108            catch (IOException e) {
109                if ("org.apache.catalina.connector.ClientAbortException".equals(e.getClass().getName()))
110                        log.debug(e, "Connection closed by client");
111                else
112                        log.error(e, "AMF message error");
113                throw e;
114            }
115            catch (Exception e) {
116                log.error(e, "AMF message error");
117                throw new ServletException(e);
118            }
119            finally {
120                GraniteContext.release();
121            }
122        }
123    
124    protected void serviceJMFAMF(GraniteConfig graniteConfig, ServicesConfig servicesConfig, ServletContext context,
125                HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {            
126            
127        log.debug(">> Incoming JMF+AMF request from: %s", request.getRequestURL());
128        
129        SharedContext jmfSharedContext = GraniteConfigListener.getSharedContext(context);
130        if (jmfSharedContext == null)
131                throw GraniteConfigListener.newSharedContextNotInitializedException();
132
133            InputStream is = null;
134            OutputStream os = null;
135            
136            try {
137                is = request.getInputStream();
138                
139                HttpGraniteContext.createThreadIntance(
140                    graniteConfig, servicesConfig, context,
141                    request, response
142                );
143        
144                log.debug(">> Deserializing JMF+AMF request...");
145        
146                @SuppressWarnings("all") // JDK7 warning (Resource leak: 'deserializer' is never closed)...
147                        JMFDeserializer deserializer = new JMFDeserializer(is, jmfSharedContext);
148                AMF0Message amf0Request = (AMF0Message)deserializer.readObject();
149
150            log.debug(">> Processing AMF0 request: %s", amf0Request);
151
152            AMF0Message amf0Response = AMF0MessageProcessor.process(amf0Request);
153        
154                log.debug("<< Serializing JMF+AMF response: %s", amf0Response);
155        
156                response.setStatus(HttpServletResponse.SC_OK);
157                response.setContentType(ContentType.JMF_AMF.mimeType());
158                response.setDateHeader("Expire", 0L);
159                response.setHeader("Cache-Control", "no-store");
160                
161                os = response.getOutputStream();
162                
163                @SuppressWarnings("all") // JDK7 warning (Resource leak: 'serializer' is never closed)...
164                        JMFSerializer serializer = new JMFSerializer(os, jmfSharedContext);
165                serializer.writeObject(amf0Response);
166                
167                response.flushBuffer();
168            }
169            catch (IOException e) {
170                if ("org.apache.catalina.connector.ClientAbortException".equals(e.getClass().getName()))
171                        log.debug(e, "Connection closed by client");
172                else
173                        log.error(e, "JMF+AMF message error");
174                throw e;
175            }
176            catch (Exception e) {
177                log.error(e, "JMF+AMF message error");
178                throw new ServletException(e);
179            }
180            finally {
181                GraniteContext.release();
182            }
183        }
184}