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.File;
027import java.io.FileOutputStream;
028import java.io.IOException;
029import java.io.InputStream;
030import java.io.OutputStream;
031
032import javax.servlet.Filter;
033import javax.servlet.FilterChain;
034import javax.servlet.FilterConfig;
035import javax.servlet.ServletException;
036import javax.servlet.ServletInputStream;
037import javax.servlet.ServletOutputStream;
038import javax.servlet.ServletRequest;
039import javax.servlet.ServletResponse;
040import javax.servlet.http.HttpServletRequest;
041import javax.servlet.http.HttpServletRequestWrapper;
042import javax.servlet.http.HttpServletResponse;
043import javax.servlet.http.HttpServletResponseWrapper;
044
045import org.granite.logging.Logger;
046import org.granite.util.ServletParams;
047
048/**
049 * @author Franck WOLFF
050 */
051public 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}