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