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.ByteArrayInputStream;
025import java.io.ByteArrayOutputStream;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.OutputStream;
029import java.io.PrintStream;
030
031import javax.servlet.Filter;
032import javax.servlet.FilterChain;
033import javax.servlet.FilterConfig;
034import javax.servlet.ServletException;
035import javax.servlet.ServletInputStream;
036import javax.servlet.ServletOutputStream;
037import javax.servlet.ServletRequest;
038import javax.servlet.ServletResponse;
039import javax.servlet.http.HttpServletRequest;
040import javax.servlet.http.HttpServletRequestWrapper;
041import javax.servlet.http.HttpServletResponse;
042import javax.servlet.http.HttpServletResponseWrapper;
043
044import org.granite.config.GraniteConfigListener;
045import org.granite.logging.Logger;
046import org.granite.messaging.jmf.JMFDumper;
047import org.granite.messaging.jmf.SharedContext;
048import org.granite.util.ContentType;
049
050/**
051 * @author Franck WOLFF
052 */
053public class JMFDumpFilter implements Filter {
054
055    private static final Logger log = Logger.getLogger(JMFDumpFilter.class);
056    
057    private SharedContext jmfSharedContext = null;
058
059    public void init(FilterConfig config) throws ServletException {
060        jmfSharedContext = GraniteConfigListener.getDumpSharedContext(config.getServletContext());
061        if (jmfSharedContext == null)
062                throw GraniteConfigListener.newSharedContextNotInitializedException();
063    }
064
065    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
066        throws IOException, ServletException {
067
068        if (!ContentType.JMF_AMF.mimeType().equals(request.getContentType())) {
069                log.info("Ignoring request with content-type: " + request.getContentType());
070                chain.doFilter(request, response);
071        }
072        else {
073                DumpRequestWrapper requestWrapper = new DumpRequestWrapper((HttpServletRequest)request);
074                DumpResponseWrapper responseWrapper= new DumpResponseWrapper((HttpServletResponse)response);
075        
076                chain.doFilter(requestWrapper, responseWrapper);
077        }
078    }
079
080    public void destroy() {
081        jmfSharedContext = null;
082    }
083
084    private void dumpBytes(String label, byte[] bytes) throws IOException {
085        final String encoding = "UTF-8";
086        
087        ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
088        PrintStream ps = new PrintStream(baos, true, encoding);
089        
090        JMFDumper dumper = new JMFDumper(new ByteArrayInputStream(bytes), jmfSharedContext, ps);
091        dumper.dump();
092        dumper.close();
093        
094        log.info("[JMF %s (%d bytes)]\n%s", label.toUpperCase(), bytes.length, new String(baos.toByteArray(), encoding));
095    }
096
097    class DumpRequestWrapper extends HttpServletRequestWrapper {
098
099        private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
100
101        public DumpRequestWrapper(HttpServletRequest request) {
102            super(request);
103        }
104
105        @Override
106        public ServletInputStream getInputStream() throws IOException {
107
108            final InputStream is = getRequest().getInputStream();
109
110            return new ServletInputStream() {
111                
112                @Override
113                public int read() throws IOException {
114                        int b = is.read();
115                        if (b != -1)
116                                baos.write(b);
117                    return b;
118                }
119
120                                @Override
121                                public int available() throws IOException {
122                                        return is.available();
123                                }
124
125                                @Override
126                                public void close() throws IOException {
127                                        is.close();
128                                        
129                                        dumpBytes("request", baos.toByteArray());
130                                }
131            };
132        }
133    }
134
135    class DumpResponseWrapper extends HttpServletResponseWrapper {
136
137        private final ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
138
139        public DumpResponseWrapper(HttpServletResponse response) {
140            super(response);
141        }
142
143        @Override
144        public ServletOutputStream getOutputStream() throws IOException {
145
146                final OutputStream os = getResponse().getOutputStream();
147                
148            return new ServletOutputStream() {
149                @Override
150                public void write(int b) throws IOException {
151                    baos.write(b);
152                    os.write(b);
153                }
154
155                                @Override
156                                public void close() throws IOException {
157                                        os.close();
158                                        
159                                        dumpBytes("response", baos.toByteArray());
160                                }
161            };
162        }
163    }
164}