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    
015    package org.apache.tapestry.web;
016    
017    import java.io.IOException;
018    import java.io.OutputStream;
019    import java.io.PrintWriter;
020    
021    import javax.servlet.http.HttpServletResponse;
022    
023    import org.apache.commons.logging.Log;
024    import org.apache.commons.logging.LogFactory;
025    import org.apache.hivemind.ApplicationRuntimeException;
026    import org.apache.hivemind.util.Defense;
027    import 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     */
036    public 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    }