001// Copyright 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry.web;
016
017import java.io.IOException;
018import java.io.OutputStream;
019import java.io.PrintWriter;
020
021import javax.servlet.http.HttpServletResponse;
022
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.apache.hivemind.ApplicationRuntimeException;
026import org.apache.hivemind.util.Defense;
027import org.apache.tapestry.util.ContentType;
028
029/**
030 * Adapts {@link javax.servlet.http.HttpServletResponse} as
031 * {@link org.apache.tapestry.web.WebResponse}.
032 * 
033 * @author Howard M. Lewis Ship
034 * @since 4.0
035 */
036public class ServletWebResponse implements WebResponse
037{
038    private static final Log DEFAULT_LOG = LogFactory.getLog(ServletWebResponse.class);
039
040    private final Log _log;
041
042    private final boolean _tomcatPatch;
043
044    private final HttpServletResponse _servletResponse;
045
046    private boolean _needsReset;
047
048    private ContentType _printWriterContentType;
049
050    public ServletWebResponse(HttpServletResponse response)
051    {
052        this(response, DEFAULT_LOG, Boolean.getBoolean("org.apache.tapestry.607-patch"));
053    }
054
055    /**
056     * Alternate constructor used by some tests.
057     */
058    ServletWebResponse(HttpServletResponse response, Log log, boolean tomcatPatch)
059    {
060        Defense.notNull(response, "response");
061        Defense.notNull(log, "log");
062
063        _servletResponse = response;
064        _log = log;
065        _tomcatPatch = tomcatPatch;
066    }
067
068    public OutputStream getOutputStream(ContentType contentType)
069    {
070        Defense.notNull(contentType, "contentType");
071
072        _servletResponse.setContentType(contentType.getMimeType());
073
074        try
075        {
076            return _servletResponse.getOutputStream();
077        }
078        catch (IOException ex)
079        {
080            throw new ApplicationRuntimeException(WebMessages.streamOpenError(contentType, ex),
081                    null, ex);
082        }
083    }
084
085    public PrintWriter getPrintWriter(ContentType contentType) throws IOException
086    {
087        Defense.notNull(contentType, "contentType");
088
089        if (_needsReset)
090            reset();
091
092        _needsReset = true;
093        
094        if (_printWriterContentType == null || ! _tomcatPatch)
095        {
096            _servletResponse.setContentType(contentType.toString());
097            _printWriterContentType = contentType;
098        }
099        else
100        {
101            // This is a workaround for a tomcat bug; it takes effect when a page is reset so that
102            // the exception page (typically) can be rendered. See TAPESTRY-607 for details.
103
104            if (!_printWriterContentType.equals(contentType))
105                _log.warn(WebMessages.contentTypeUnchanged(_printWriterContentType, contentType));
106        }
107
108        try
109        {
110            return _servletResponse.getWriter();
111        }
112        catch (IOException ex)
113        {
114            throw new ApplicationRuntimeException(WebMessages.writerOpenError(contentType, ex),
115                    null, ex);
116        }
117    }
118
119    public String encodeURL(String url)
120    {
121        return _servletResponse.encodeURL(url);
122    }
123
124    public void reset()
125    {
126        try
127        {
128            _servletResponse.reset();
129        }
130        catch (IllegalStateException ex)
131        {
132            _log.error(WebMessages.resetFailed(ex), ex);
133        }
134    }
135
136    public void setContentLength(int length)
137    {
138        _servletResponse.setContentLength(length);
139    }
140
141    public String getNamespace()
142    {
143        return "";
144    }
145
146    public void setDateHeader(String name, long date)
147    {
148        _servletResponse.setDateHeader(name, date);
149    }
150
151    public void setStatus(int status)
152    {
153        _servletResponse.setStatus(status);
154    }
155
156    public void setHeader(String name, String value)
157    {
158        _servletResponse.setHeader(name, value);
159    }
160
161    public void setIntHeader(String name, int value)
162    {
163        _servletResponse.setIntHeader(name, value);
164    }
165
166    public void sendError(int statusCode, String message) throws IOException
167    {
168        _servletResponse.sendError(statusCode, message);
169    }
170
171}