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