001    /*
002    Copyright (c) 1996-2012, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    package org.hd.d.pg2k.webSvr.util;
030    
031    //import ORG.hd.d.IsDebug;
032    
033    import java.io.IOException;
034    
035    import javax.servlet.Filter;
036    import javax.servlet.FilterChain;
037    import javax.servlet.FilterConfig;
038    import javax.servlet.ServletException;
039    import javax.servlet.ServletRequest;
040    import javax.servlet.ServletResponse;
041    import javax.servlet.http.HttpServletResponse;
042    
043    /**Compresses XML by removing redundant whitespace (etc).
044     * Should quickly reduce the size of many XML documents on the fly
045     * without changing their semantics.
046     * <p>
047     * This will allow document streaming (ie incremental processing)
048     * and will support flush() to allow the push of partial documents,
049     * although this may not be able to push partial XML atoms
050     * (eg partial elements and entities).
051     * <p>
052     * To avoid upsetting some older consumers of XML,
053     * such as old mobile phones and PDAs,
054     * this may avoid some transformations such as
055     * <code>&lt;x&gt;&lt;/x&gt;</code> to <code>&lt;x/&gt;</code>.
056     * <p>
057     * To avoid upsetting older HTML consumers of XHTML
058     * this may avoid some transformations such as
059     * <code>&lt;br /&gt;</code> to <code>&lt;br/&gt;</code>.
060     */
061    public final class XMLCompressionFilter implements Filter
062        {
063        /**Our logger which falls back to System.out if servlet log not available; never null. */
064        private final WebUtils.ServletLoggerWithFallback logger = new WebUtils.ServletLoggerWithFallback();
065    
066        /**The filter configuration object we are associated with.
067         * If this value is null, this filter instance is not currently configured.
068         */
069        private FilterConfig config;
070    
071        public FilterConfig getFilterConfig()
072            {
073            return (config);
074            }
075    
076        public void setFilterConfig(final FilterConfig c)
077            {
078            config = c;
079            logger.setContext((c == null) ? null : c.getServletContext());
080            }
081    
082        /**Place this filter into service.
083         * @param filterConfig  filter configuration object; null to unset
084         */
085        public void init(final FilterConfig filterConfig)
086            {
087            config = filterConfig;
088            logger.setContext((filterConfig == null) ? null : filterConfig.getServletContext());
089            }
090    
091        /**Take this filter out of service. */
092        public void destroy()
093            {
094            config = null;
095            logger.setContext(null);
096            }
097    
098        /**Compacts the (XML) reponse text when possible.
099         */
100        public void doFilter(final ServletRequest request,
101                             final ServletResponse response,
102                             final FilterChain chain)
103            throws IOException, ServletException
104            {
105            if(response instanceof HttpServletResponse)
106                {
107                final XMLCompressionServletResponseWrapper wrappedResponse =
108                    new XMLCompressionServletResponseWrapper((HttpServletResponse) response);
109                try { chain.doFilter(request, wrappedResponse); }
110                finally { wrappedResponse.finishResponse(); }
111                return;
112                }
113    
114            // Pass on unchanged...
115            chain.doFilter(request, response);
116            }
117        }
118