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     */
022    package org.granite.messaging.webapp;
023    
024    import java.io.ByteArrayInputStream;
025    import java.io.ByteArrayOutputStream;
026    import java.io.File;
027    import java.io.FileOutputStream;
028    import java.io.IOException;
029    import java.io.InputStream;
030    import java.io.OutputStream;
031    
032    import javax.servlet.Filter;
033    import javax.servlet.FilterChain;
034    import javax.servlet.FilterConfig;
035    import javax.servlet.ServletException;
036    import javax.servlet.ServletInputStream;
037    import javax.servlet.ServletOutputStream;
038    import javax.servlet.ServletRequest;
039    import javax.servlet.ServletResponse;
040    import javax.servlet.http.HttpServletRequest;
041    import javax.servlet.http.HttpServletRequestWrapper;
042    import javax.servlet.http.HttpServletResponse;
043    import javax.servlet.http.HttpServletResponseWrapper;
044    
045    import org.granite.logging.Logger;
046    import org.granite.util.ServletParams;
047    
048    /**
049     * @author Franck WOLFF
050     */
051    public class DumpFilter implements Filter {
052    
053        private static final Logger log = Logger.getLogger(DumpFilter.class);
054        private static final String HEXS = "0123456789ABCDEF";
055        private static final String DUMP_DIR = "dumpDir";
056    
057        File dumpDir = null;
058    
059        public void init(FilterConfig config) throws ServletException {
060            String dumpDirString = ServletParams.get(config, DUMP_DIR, String.class, null);
061            if (dumpDirString != null) {
062                File dumpDir = new File(dumpDirString);
063                if (!dumpDir.exists() || !dumpDir.isDirectory() || !dumpDir.canWrite())
064                    log.warn("Ignoring dump directory (is it a writable directory?): %s", dumpDir);
065                else
066                    this.dumpDir = dumpDir;
067            }
068        }
069    
070        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
071            throws IOException, ServletException {
072    
073            DumpRequestWrapper requestWrapper = new DumpRequestWrapper((HttpServletRequest)request);
074            DumpResponseWrapper responseWrapper= new DumpResponseWrapper((HttpServletResponse)response);
075    
076            dumpBytes("request", requestWrapper.getBytes());
077            chain.doFilter(requestWrapper, responseWrapper);
078            dumpBytes("response", responseWrapper.getBytes());
079        }
080    
081        public void destroy() {
082            dumpDir = null;
083        }
084    
085        private void dumpBytes(String label, byte[] bytes) {
086            StringBuilder hexSb = new StringBuilder();
087            StringBuilder charSb = new StringBuilder();
088    
089            for (int i = 0; i < bytes.length; i++) {
090                int b = bytes[i] & 0xFF;
091                if (hexSb.length() > 0) {
092                    hexSb.append(' ');
093                    charSb.append(' ');
094                }
095                hexSb.append(HEXS.charAt(b >> 4)).append(HEXS.charAt(b & 0x0F));
096                if (b >= 0x20 && b <= 0x7e)
097                    charSb.append(' ').append((char)b);
098                else
099                    charSb.append("##");
100            }
101    
102            log.info("[RAW %s] {\n%s\n%s\n}", label.toUpperCase(), hexSb.toString(), charSb.toString());
103    
104            if (dumpDir != null) {
105                File file = new File(dumpDir.getPath() + File.separator + label + "_" + System.currentTimeMillis() + ".amf");
106                for (int i = 1; i < 100 && file.exists(); i++)
107                    file = new File(file.getAbsolutePath() + "." + i);
108    
109                OutputStream os = null;
110                try {
111                    os = new FileOutputStream(file);
112                    os.write(bytes);
113                } catch (Exception e) {
114                    log.error(e, "Could not write dump file: %s", file);
115                } finally {
116                    if (os != null) try {
117                        os.close();
118                    } catch (Exception e) {
119                    }
120                }
121            }
122        }
123    
124        class DumpRequestWrapper extends HttpServletRequestWrapper {
125    
126            private byte[] bytes = null;
127    
128            public DumpRequestWrapper(HttpServletRequest request) throws IOException {
129                super(request);
130    
131                setCharacterEncoding("UTF-8");
132    
133                InputStream is = null;
134                try {
135                    is = request.getInputStream();
136    
137                    ByteArrayOutputStream out = new ByteArrayOutputStream(128);
138                    for (int b = is.read(); b != -1; b = is.read())
139                        out.write(b);
140    
141                    this.bytes = out.toByteArray();
142                } catch (Exception e) {
143                    throw new RuntimeException(e);
144                }
145            }
146    
147            @Override
148            public ServletInputStream getInputStream() throws IOException {
149    
150                final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
151    
152                return new ServletInputStream() {
153                    @Override
154                    public int read() throws IOException {
155                        return bais.read();
156                    }
157                };
158            }
159    
160            public byte[] getBytes() {
161                return bytes;
162            }
163        }
164    
165        class DumpResponseWrapper extends HttpServletResponseWrapper {
166    
167            private ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
168            private ServletOutputStream out = null;
169    
170            public DumpResponseWrapper(HttpServletResponse response) throws IOException {
171                super(response);
172                this.out = response.getOutputStream();
173            }
174    
175            @Override
176            public ServletOutputStream getOutputStream() throws IOException {
177    
178                return new ServletOutputStream() {
179                    @Override
180                    public void write(int b) throws IOException {
181                        baos.write(b);
182                        out.write(b);
183                    }
184                };
185            }
186    
187            public byte[] getBytes() {
188                return baos.toByteArray();
189            }
190        }
191    }