001 /* 002 * Copyright 2004-2006 Geert Bevin <gbevin[remove] at uwyn dot com> 003 * Distributed under the terms of either: 004 * - the common development and distribution license (CDDL), v1.0; or 005 * - the GNU Lesser General Public License, v2.1 or later 006 * $Id: HighlightFilter.java 3108 2006-03-13 18:03:00Z gbevin $ 007 */ 008 package com.uwyn.jhighlight.servlet; 009 010 import javax.servlet.*; 011 012 import com.uwyn.jhighlight.renderer.Renderer; 013 import com.uwyn.jhighlight.renderer.XhtmlRendererFactory; 014 import com.uwyn.jhighlight.tools.FileUtils; 015 import java.io.ByteArrayInputStream; 016 import java.io.ByteArrayOutputStream; 017 import java.io.IOException; 018 import java.io.InputStream; 019 import java.io.OutputStream; 020 import javax.servlet.http.HttpServletRequest; 021 import javax.servlet.http.HttpServletRequestWrapper; 022 import javax.servlet.http.HttpServletResponse; 023 import javax.servlet.http.HttpServletResponseWrapper; 024 025 /** 026 * A servlet filter that offers on-the-fly syntax highlighting for Java, HTML, 027 * XHTML, XML and LZX files. 028 * <p>The filter should be declared in a similar fashion as this: 029 * <pre><filter> 030 * <filter-name>jhighlight</filter-name> 031 * <filter-class>com.uwyn.jhighlight.servlet.HighlightFilter</filter-class> 032 *</filter> 033 * 034 *<filter-mapping> 035 * <filter-name>jhighlight</filter-name> 036 * <url-pattern>/*</url-pattern> 037 *</filter-mapping></pre> 038 * <p>It will respond to files with the following extensions: 039 * <code>.javas</code>, <code>.htmls</code>, <code>.htms</code>, 040 * <code>.xhtmls</code>, <code>.xmls</code> and <code>.lzxs</code>. These will 041 * be automatically mapped to files without the last <code>s</code> in the 042 * filenames. Thus, for example, a request like this: 043 * <pre>http://myhost.com/folder/MySource.javas</pre> 044 * <p>will retrieve this file: 045 * <pre>http://myhost.com/folder/MySource.java</pre> 046 * <p>The contents of this file will be automatically highlighted and the 047 * resulting HTML will be served. 048 * 049 * @author Geert Bevin (gbevin[remove] at uwyn dot com) 050 * @version $Revision: 3108 $ 051 * @since 1.0 052 */ 053 public final class HighlightFilter implements Filter 054 { 055 public void init(FilterConfig filterConfig) 056 { 057 } 058 059 public void destroy() 060 { 061 } 062 063 public void doFilter(ServletRequest request, 064 ServletResponse response, FilterChain chain) 065 throws IOException, ServletException 066 { 067 if (request instanceof HttpServletRequest && 068 response instanceof HttpServletResponse) 069 { 070 HttpServletRequest http_request = (HttpServletRequest)request; 071 HttpServletResponse http_response = (HttpServletResponse)response; 072 073 Renderer renderer = null; 074 String uri = http_request.getRequestURI(); 075 String extension = FileUtils.getExtension(uri); 076 if (extension != null && 077 extension.endsWith("s")) 078 { 079 renderer = XhtmlRendererFactory.getRenderer(extension.substring(0, extension.length()-1)); 080 } 081 082 if (renderer != null) 083 { 084 SourceRequestWrapper request_wrapper = new SourceRequestWrapper(http_request); 085 CharResponseWrapper response_wrapper = new CharResponseWrapper(http_response); 086 087 chain.doFilter(request_wrapper, response_wrapper); 088 089 OutputStream out = response.getOutputStream(); 090 try 091 { 092 if (HttpServletResponse.SC_OK == response_wrapper.getStatus()) 093 { 094 InputStream is = new ByteArrayInputStream(response_wrapper.getWrappedOutputStream().toByteArray()); 095 ByteArrayOutputStream os = new ByteArrayOutputStream(); 096 097 String encoding = request.getCharacterEncoding(); 098 if (null == encoding) 099 { 100 encoding = "UTF-8"; 101 } 102 103 renderer.highlight(http_request.getServletPath().substring(1), is, os, encoding, false); 104 105 String highlighted = os.toString("ISO-8859-1"); 106 107 response.setContentType("text/html"); 108 response.setContentLength(highlighted.length()); 109 out.write(highlighted.getBytes("ISO-8859-1")); 110 } 111 else 112 { 113 out.write(response_wrapper.getWrappedOutputStream().toByteArray()); 114 } 115 } 116 finally 117 { 118 out.close(); 119 } 120 } 121 else 122 { 123 chain.doFilter(request, response); 124 } 125 } 126 else 127 { 128 chain.doFilter(request, response); 129 } 130 } 131 132 private static class SourceRequestWrapper extends HttpServletRequestWrapper 133 { 134 public SourceRequestWrapper(HttpServletRequest request) 135 { 136 super(request); 137 } 138 139 public String getServletPath() 140 { 141 String path = super.getServletPath(); 142 return path.substring(0, path.length() - 1); 143 } 144 145 public String getPathTranslated() 146 { 147 String path = super.getPathTranslated(); 148 return path.substring(0, path.length() - 1); 149 } 150 151 public String getRequestURI() 152 { 153 String uri = super.getRequestURI(); 154 return uri.substring(0, uri.length() - 1); 155 } 156 157 public StringBuffer getRequestURL() 158 { 159 StringBuffer url = super.getRequestURL(); 160 url.setLength(url.length() - 1); 161 return url; 162 } 163 } 164 165 private static class CharResponseWrapper extends HttpServletResponseWrapper 166 { 167 private ServletOutputStreamWrapper mOutput; 168 private int mStatus = HttpServletResponse.SC_OK; 169 170 public ServletOutputStreamWrapper getWrappedOutputStream() 171 { 172 return mOutput; 173 } 174 175 public CharResponseWrapper(HttpServletResponse response) 176 { 177 super(response); 178 179 mOutput = new ServletOutputStreamWrapper(); 180 } 181 182 public ServletOutputStream getOutputStream() 183 throws IOException 184 { 185 return mOutput; 186 } 187 188 public void setStatus(int status) 189 { 190 mStatus = status; 191 192 super.setStatus(status); 193 } 194 195 public void sendError(int status, String msg) 196 throws IOException 197 { 198 mStatus = status; 199 200 super.sendError(status, msg); 201 } 202 203 public void sendError(int status) 204 throws IOException 205 { 206 mStatus = status; 207 208 super.sendError(status); 209 } 210 211 public int getStatus() 212 { 213 return mStatus; 214 } 215 } 216 217 private static class ServletOutputStreamWrapper extends ServletOutputStream 218 { 219 protected ByteArrayOutputStream mOutput; 220 221 public ServletOutputStreamWrapper() 222 { 223 mOutput = new ByteArrayOutputStream(); 224 } 225 226 public void write(int b) throws IOException 227 { 228 mOutput.write(b); 229 } 230 231 public byte[] toByteArray() 232 { 233 return mOutput.toByteArray(); 234 } 235 } 236 }