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 org.apache.commons.logging.Log;
018    import org.apache.commons.logging.LogFactory;
019    import org.apache.hivemind.ApplicationRuntimeException;
020    import org.apache.hivemind.util.Defense;
021    import org.apache.tapestry.util.ContentType;
022    
023    import javax.servlet.http.HttpServletResponse;
024    import java.io.IOException;
025    import java.io.OutputStream;
026    import java.io.PrintWriter;
027    
028    /**
029     * Adapts {@link javax.servlet.http.HttpServletResponse} as
030     * {@link org.apache.tapestry.web.WebResponse}.
031     * 
032     * @author Howard M. Lewis Ship
033     * @since 4.0
034     */
035    public class ServletWebResponse implements WebResponse
036    {
037        private static final Log DEFAULT_LOG = LogFactory.getLog(ServletWebResponse.class);
038    
039        private final Log _log;
040    
041        private final boolean _tomcatPatch;
042    
043        private final HttpServletResponse _servletResponse;
044    
045        private boolean _needsReset;
046    
047        private ContentType _printWriterContentType;
048    
049        public ServletWebResponse(HttpServletResponse response)
050        {
051            this(response, DEFAULT_LOG, Boolean.getBoolean("org.apache.tapestry.607-patch"));
052        }
053    
054        /**
055         * Alternate constructor used by some tests.
056         *
057         * @param response
058         *          The wrapped response.
059         * @param log
060         *          Logger.
061         * @param tomcatPatch
062         *          Whether or not to apply tomcat workaround.
063         */
064        ServletWebResponse(HttpServletResponse response, Log log, boolean tomcatPatch)
065        {
066            Defense.notNull(response, "response");
067            Defense.notNull(log, "log");
068    
069            _servletResponse = response;
070            _log = log;
071            _tomcatPatch = tomcatPatch;
072        }
073    
074        public OutputStream getOutputStream(ContentType contentType)
075        {
076            Defense.notNull(contentType, "contentType");
077    
078            _servletResponse.setContentType(contentType.getMimeType());
079    
080            try
081            {
082                return _servletResponse.getOutputStream();
083            }
084            catch (IOException ex)
085            {
086                throw new ApplicationRuntimeException(WebMessages.streamOpenError(contentType, ex),
087                        null, ex);
088            }
089        }
090    
091        public PrintWriter getPrintWriter(ContentType contentType) throws IOException
092        {
093            Defense.notNull(contentType, "contentType");
094    
095            if (_needsReset)
096                reset();
097    
098            _needsReset = true;
099            
100            if (_printWriterContentType == null || ! _tomcatPatch)
101            {
102                _servletResponse.setContentType(contentType.toString());
103                _printWriterContentType = contentType;
104            }
105            else
106            {
107                // This is a workaround for a tomcat bug; it takes effect when a page is reset so that
108                // the exception page (typically) can be rendered. See TAPESTRY-607 for details.
109    
110                if (!_printWriterContentType.equals(contentType))
111                    _log.warn(WebMessages.contentTypeUnchanged(_printWriterContentType, contentType));
112            }
113    
114            try
115            {
116                return _servletResponse.getWriter();
117            }
118            catch (IOException ex)
119            {
120                throw new ApplicationRuntimeException(WebMessages.writerOpenError(contentType, ex),
121                        null, ex);
122            }
123        }
124    
125        public String encodeURL(String url)
126        {
127            return _servletResponse.encodeURL(url);
128        }
129    
130        public void reset()
131        {
132            try
133            {
134                _servletResponse.reset();
135            }
136            catch (IllegalStateException ex)
137            {
138                _log.error(WebMessages.resetFailed(ex), ex);
139            }
140        }
141    
142        public void setContentLength(int length)
143        {
144            _servletResponse.setContentLength(length);
145        }
146    
147        public String getNamespace()
148        {
149            return "";
150        }
151    
152        public void setDateHeader(String name, long date)
153        {
154            _servletResponse.setDateHeader(name, date);
155        }
156    
157        public void setStatus(int status)
158        {
159            _servletResponse.setStatus(status);
160        }
161    
162        public void setHeader(String name, String value)
163        {
164            _servletResponse.setHeader(name, value);
165        }
166    
167        public void setIntHeader(String name, int value)
168        {
169            _servletResponse.setIntHeader(name, value);
170        }
171    
172        public void sendError(int statusCode, String message) throws IOException
173        {
174            _servletResponse.sendError(statusCode, message);
175        }
176    
177    }