Package org.grails.web.sitemesh

Source Code of org.grails.web.sitemesh.GrailsPageResponseWrapper$GrailsBuffer

/*
* Copyright 2004-2005 Graeme Rocher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.grails.web.sitemesh;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.grails.web.servlet.mvc.GrailsWebRequest;
import org.grails.buffer.GrailsPrintWriterAdapter;
import org.grails.buffer.StreamByteBuffer;
import org.grails.buffer.StreamCharBuffer;
import org.grails.web.util.WebUtils;

import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
import com.opensymphony.module.sitemesh.PageParserSelector;
import com.opensymphony.module.sitemesh.filter.HttpContentType;
import com.opensymphony.module.sitemesh.filter.RoutableServletOutputStream;
import com.opensymphony.module.sitemesh.filter.TextEncoder;

/**
* @author Graeme Rocher
* @since 1.0.4
*/
public class GrailsPageResponseWrapper extends HttpServletResponseWrapper{

    private final GrailsRoutablePrintWriter routablePrintWriter;
    private final RoutableServletOutputStream routableServletOutputStream;
    private final PageParserSelector parserSelector;
    private final HttpServletRequest request;

    private GrailsBuffer buffer;
    private boolean parseablePage = false;
    private GSPSitemeshPage gspSitemeshPage;

    public GrailsPageResponseWrapper(final HttpServletRequest request, final HttpServletResponse response,
            PageParserSelector parserSelector) {
        super(response);
        this.parserSelector = parserSelector;

        routablePrintWriter = GrailsRoutablePrintWriter.newInstance(new GrailsRoutablePrintWriter.DestinationFactory() {
            public PrintWriter activateDestination() throws IOException {
                return response.getWriter();
            }
        });
        routableServletOutputStream = new RoutableServletOutputStream(new RoutableServletOutputStream.DestinationFactory() {
            public ServletOutputStream create() throws IOException {
                return response.getOutputStream();
            }
        });

        this.request = request;

        gspSitemeshPage = (GSPSitemeshPage)request.getAttribute(GrailsLayoutView.GSP_SITEMESH_PAGE);
       
        applyContentType(response.getContentType());
    }

    @Override
    public void sendError(int sc) throws IOException {
        clearBuffer();
        GrailsWebRequest webRequest = GrailsWebRequest.lookup();
        try {
            super.sendError(sc);
        }
        finally {
            if(webRequest != null)
                WebUtils.storeGrailsWebRequest(webRequest);
        }
    }

    @Override
    public void sendError(int sc, String msg) throws IOException {
        clearBuffer();
        GrailsWebRequest webRequest = GrailsWebRequest.lookup();
        try {
            super.sendError(sc, msg);
        }
        finally {
            if(webRequest != null)
                WebUtils.storeGrailsWebRequest(webRequest);
        }
    }

    /**
     * Set the content-type of the request and store it so it can
     * be passed to the {@link com.opensymphony.module.sitemesh.PageParser}.
     */
    @Override
    public void setContentType(String type) {
        super.setContentType(type);

        applyContentType(type);
    }

    protected void applyContentType(String type) {
        if (type == null) {
            return;
        }

        HttpContentType httpContentType = new HttpContentType(type);

        if (parserSelector.shouldParsePage(httpContentType.getType())) {
            activateSiteMesh(httpContentType.getType(), httpContentType.getEncoding());
        }
        else {
            deactivateSiteMesh();
        }
    }

    public void activateSiteMesh(String contentType, String encoding) {
        if (parseablePage) {
            return; // already activated
        }

        buffer = new GrailsBuffer(parserSelector, contentType, encoding, gspSitemeshPage);
        routablePrintWriter.updateDestination(new GrailsRoutablePrintWriter.DestinationFactory() {
            public PrintWriter activateDestination() {
                return buffer.getWriter();
            }
        });
        routablePrintWriter.blockFlushAndClose();
        routableServletOutputStream.updateDestination(new RoutableServletOutputStream.DestinationFactory() {
            public ServletOutputStream create() {
                return buffer.getOutputStream();
            }
        });
        parseablePage = true;
    }

    public void deactivateSiteMesh() {
        parseablePage = false;
        buffer = null;
        if (gspSitemeshPage != null) {
            gspSitemeshPage.reset();
        }
        routablePrintWriter.updateDestination(new GrailsRoutablePrintWriter.DestinationFactory() {
            public PrintWriter activateDestination() throws IOException {
                return getResponse().getWriter();
            }
        });
        routablePrintWriter.unBlockFlushAndClose();
        routableServletOutputStream.updateDestination(new RoutableServletOutputStream.DestinationFactory() {
            public ServletOutputStream create() throws IOException {
                return getResponse().getOutputStream();
            }
        });
    }

    /**
     * Prevent content-length being set if page is parseable.
     */
    @Override
    public void setContentLength(int contentLength) {
        if (!parseablePage) super.setContentLength(contentLength);
    }

    /**
     * Prevent buffer from being flushed if this is a page being parsed.
     */
    @Override
    public void flushBuffer() throws IOException {
        if (!parseablePage) super.flushBuffer();
    }

    /**
     * Prevent content-length being set if page is parseable.
     */
    @Override
    public void setHeader(String name, String value) {
        if (name.toLowerCase().equals("content-type")) { // ensure ContentType is always set through setContentType()
            setContentType(value);
        }
        else if (!parseablePage || !name.toLowerCase().equals("content-length")) {
            super.setHeader(name, value);
        }
    }

    /**
     * Prevent content-length being set if page is parseable.
     */
    @Override
    public void addHeader(String name, String value) {
        if (name.toLowerCase().equals("content-type")) { // ensure ContentType is always set through setContentType()
            setContentType(value);
        }
        else if (!parseablePage || !name.toLowerCase().equals("content-length")) {
            super.addHeader(name, value);
        }
    }

    /**
     * If 'not modified' (304) HTTP status is being sent - then abort parsing, as there shouldn't be any body
     */
    @Override
    public void setStatus(int sc) {
        if (sc == HttpServletResponse.SC_NOT_MODIFIED) {
            // route any content back to the original writer.  There shouldn't be any content, but just to be safe
            deactivateSiteMesh();
        } else if (sc >= 400) {
            clearBuffer();
        }
        super.setStatus(sc);
    }

    protected void clearBuffer() {
        if (buffer != null) {
            buffer.clear();
        }
    }

    @Override
    public ServletOutputStream getOutputStream() {
        return routableServletOutputStream;
    }

    @Override
    public PrintWriter getWriter() {
        return routablePrintWriter;
    }

    public Page getPage() throws IOException {
        if (isSitemeshNotActive()) {
            return null;
        }

        GSPSitemeshPage page = (GSPSitemeshPage)request.getAttribute(GrailsLayoutView.GSP_SITEMESH_PAGE);
        if (page != null && page.isUsed()) {
            return page;
        }

        return buffer.parse();
    }

    @Override
    public void sendRedirect(String location) throws IOException {
        clearBuffer();
        super.sendRedirect(location);
    }

    public boolean isUsingStream() {
        return buffer != null && buffer.isUsingStream();
    }

    public char[] getContents() throws IOException {
        if (isSitemeshNotActive()) {
            return null;
        }

        return buffer.getContents();
    }

    public boolean isSitemeshActive() {
        return !isSitemeshNotActive();
    }

    public boolean isGspSitemeshActive() {
        return (gspSitemeshPage != null && gspSitemeshPage.isUsed());
    }

    private boolean isSitemeshNotActive() {
        return !parseablePage;
    }

    private static class GrailsBuffer {
        private final PageParserSelector parserSelector;
        private final String contentType;
        private final String encoding;
        private final static TextEncoder TEXT_ENCODER = new TextEncoder();

        private StreamCharBuffer charBuffer;
        private GrailsPrintWriterAdapter exposedWriter;
        private StreamByteBuffer byteBuffer;
        private ServletOutputStream exposedStream;

        private GSPSitemeshPage gspSitemeshPage;

        public GrailsBuffer(PageParserSelector parserSelector, String contentType, String encoding, GSPSitemeshPage gspSitemeshPage) {
            this.parserSelector = parserSelector;
            this.contentType = contentType;
            this.encoding = encoding;
            this.gspSitemeshPage = gspSitemeshPage;
        }

        public void clear() {
            if (charBuffer != null) {
                charBuffer.clear();
            } else if (byteBuffer != null) {
                byteBuffer.clear();
            }
            if (gspSitemeshPage != null) {
                gspSitemeshPage.reset();
            }
        }
           
        private char[] getContents() throws IOException {
            if (charBuffer != null) {
                if (!charBuffer.isEmpty()) {
                    return charBuffer.toCharArray();
                } else {
                    return null;
                }
            }
            if (byteBuffer != null) {
                return TEXT_ENCODER.encode(byteBuffer.readAsByteArray(), encoding);
            }

            return new char[0];
        }

        public Page parse() throws IOException {
            PageParser pageParser = parserSelector.getPageParser(contentType);
            return pageParser != null ? pageParser.parse(getContents()) : null;
        }

        public PrintWriter getWriter() {
            if (charBuffer == null) {
                if (byteBuffer != null) {
                    throw new IllegalStateException("response.getWriter() called after response.getOutputStream()");
                }
                charBuffer=new StreamCharBuffer();
                charBuffer.setNotifyParentBuffersEnabled(false);
                if (gspSitemeshPage != null) {
                    gspSitemeshPage.setPageBuffer(charBuffer);
                }
                exposedWriter = GrailsPrintWriterAdapter.newInstance(charBuffer.getWriter());
            }
            return exposedWriter;
        }

        public ServletOutputStream getOutputStream() {
            if (byteBuffer == null) {
                if (charBuffer != null) {
                    throw new IllegalStateException("response.getOutputStream() called after response.getWriter()");
                }
                byteBuffer = new StreamByteBuffer();
                final OutputStream out=byteBuffer.getOutputStream();
                exposedStream = new ServletOutputStream() {
                    @Override
                    public void write(byte[] b, int off, int len) throws IOException {
                        out.write(b, off, len);
                    }

                    @Override
                    public void write(byte[] b) throws IOException {
                        out.write(b);
                    }

                    @Override
                    public void write(int b) throws IOException {
                        out.write(b);
                    }
                };
            }
            return exposedStream;
        }

        public boolean isUsingStream() {
            return byteBuffer != null;
        }
    }
}
TOP

Related Classes of org.grails.web.sitemesh.GrailsPageResponseWrapper$GrailsBuffer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.