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