1 /*
2 * Copyright 2008-2019 by Emeric Vernat
3 *
4 * This file is part of Java Melody.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package net.bull.javamelody.internal.web;
19
20 import java.io.IOException;
21 import java.io.OutputStreamWriter;
22 import java.io.PrintWriter;
23
24 import javax.servlet.ServletOutputStream;
25 import javax.servlet.http.HttpServletResponse;
26 import javax.servlet.http.HttpServletResponseWrapper;
27
28 /**
29 * Implémentation de {@link HttpServletResponseWrapper} permettant d'encapsuler l'outputStream,
30 * par exemple pour calculer la taille du flux ou pour le compresser.
31 * @author Emeric Vernat
32 */
33 abstract class FilterServletResponseWrapper extends HttpServletResponseWrapper {
34 private ServletOutputStream stream;
35 private PrintWriter writer;
36 private int status = HttpServletResponse.SC_OK;
37
38 /**
39 * Constructeur.
40 * @param response HttpServletResponse
41 */
42 FilterServletResponseWrapper(HttpServletResponse response) {
43 super(response);
44 assert response != null;
45 }
46
47 HttpServletResponse getHttpServletResponse() {
48 return (HttpServletResponse) getResponse();
49 }
50
51 /**
52 * @return ServletOutputStream
53 */
54 ServletOutputStream getStream() {
55 return stream;
56 }
57
58 /** {@inheritDoc} */
59 @Override
60 public void reset() {
61 super.reset();
62 status = 0;
63 stream = null;
64 writer = null;
65 }
66
67 /**
68 * Retourne le status définit par setStatus ou sendError.
69 * @return int
70 */
71 public int getCurrentStatus() {
72 // cette méthode s'appele getCurrentStatus pour ne pas interférer avec getStatus
73 // dans servlet api 3.0, tout en restant compatible avec servlet api 2.5
74 return status;
75 }
76
77 /** {@inheritDoc} */
78 @Override
79 public void setStatus(int status) {
80 super.setStatus(status);
81 this.status = status;
82 }
83
84 /** {@inheritDoc} */
85 @Override
86 public void sendError(int error) throws IOException {
87 super.sendError(error);
88 this.status = error;
89 }
90
91 /** {@inheritDoc} */
92 @Override
93 public void sendError(int error, String message) throws IOException {
94 super.sendError(error, message);
95 this.status = error;
96 }
97
98 /**
99 * Crée et retourne un ServletOutputStream pour écrire le contenu dans la response associée.
100 * @return ServletOutputStream
101 * @throws IOException Erreur d'entrée/sortie
102 */
103 protected abstract ServletOutputStream createOutputStream() throws IOException;
104
105 /** {@inheritDoc} */
106 @Override
107 public ServletOutputStream getOutputStream() throws IOException {
108 if (writer != null) {
109 throw new IllegalStateException(
110 "getWriter() has already been called for this response");
111 }
112
113 if (stream == null) {
114 stream = createOutputStream();
115 assert stream != null;
116 }
117 return stream;
118 }
119
120 /** {@inheritDoc} */
121 @Override
122 public PrintWriter getWriter() throws IOException {
123 if (writer == null) {
124 if (stream != null) {
125 throw new IllegalStateException(
126 "getOutputStream() has already been called for this response");
127 }
128
129 try {
130 getOutputStream();
131 } catch (final IllegalStateException e) {
132 // issue 488: if a filter has called getWriter() before the MonitoringFilter, we can't call getOutputStream()
133 writer = super.getWriter();
134 return writer;
135 }
136
137 final ServletOutputStream outputStream = getOutputStream();
138 final String charEnc = getHttpServletResponse().getCharacterEncoding();
139 // HttpServletResponse.getCharacterEncoding() shouldn't return null
140 // according the spec, so feel free to remove that "if"
141 final PrintWriter result;
142 if (charEnc == null) {
143 result = new PrintWriter(outputStream);
144 } else {
145 result = new PrintWriter(new OutputStreamWriter(outputStream, charEnc));
146 }
147 writer = result;
148 }
149 return writer;
150 }
151
152 /** {@inheritDoc} */
153 @Override
154 public void flushBuffer() throws IOException {
155 if (writer != null) {
156 writer.flush();
157 } else if (stream != null) {
158 stream.flush();
159 } else {
160 // writes status code and headers when no content (issue #836)
161 super.flushBuffer();
162 }
163 }
164
165 public void flushStream() throws IOException {
166 if (writer != null) {
167 writer.flush();
168 } else if (stream != null) {
169 stream.flush();
170 }
171 }
172
173 /**
174 * Ferme le flux.
175 * @throws IOException e
176 */
177 public void close() throws IOException {
178 if (writer != null) {
179 writer.close();
180 } else if (stream != null) {
181 stream.close();
182 }
183 }
184 }
185