/*
 * Copyright 2008-2014 by Emeric Vernat
 *
 *     This file is part of Java Melody.
 *
 * 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 net.bull.javamelody;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

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

/**
 * Implémentation de HttpServletResponseWrapper permettant d'encapsuler l'outputStream,
 * par exemple pour calculer la taille du flux ou pour le compresser.
 * @author Emeric Vernat
 */
abstract class FilterServletResponseWrapper extends HttpServletResponseWrapper {
	private ServletOutputStream stream;
	private PrintWriter writer;
	private int status;

	/**
	 * Constructeur.
	 * @param response HttpServletResponse
	 */
	FilterServletResponseWrapper(HttpServletResponse response) {
		super(response);
		assert response != null;
	}

	/**
	 * @return ServletOutputStream
	 */
	ServletOutputStream getStream() {
		return stream;
	}

	/** {@inheritDoc} */
	@Override
	public void reset() {
		super.reset();
		status = 0;
		stream = null;
		writer = null;
	}

	/**
	 * Retourne le status définit par setStatus ou sendError.
	 * @return int
	 */
	public int getCurrentStatus() {
		// cette méthode s'appele getCurrentStatus pour ne pas interférer avec getStatus
		// dans servlet api 3.0, tout en restant compatible avec servlet api 2.5
		return status;
	}

	/** {@inheritDoc} */
	@Override
	public void setStatus(int status) {
		super.setStatus(status);
		this.status = status;
	}

	/** {@inheritDoc} */
	@Override
	public void sendError(int error) throws IOException {
		super.sendError(error);
		this.status = error;
	}

	/** {@inheritDoc} */
	@Override
	public void sendError(int error, String message) throws IOException {
		super.sendError(error, message);
		this.status = error;
	}

	/**
	 * Crée et retourne un ServletOutputStream pour écrire le contenu dans la response associée.
	 * @return ServletOutputStream
	 * @throws IOException   Erreur d'entrée/sortie
	 */
	protected abstract ServletOutputStream createOutputStream() throws IOException;

	/** {@inheritDoc} */
	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		if (writer != null) {
			throw new IllegalStateException("getWriter() has already been called for this response");
		}

		if (stream == null) {
			stream = createOutputStream();
			assert stream != null;
		}
		return stream;
	}

	/** {@inheritDoc} */
	@Override
	public PrintWriter getWriter() throws IOException {
		if (writer == null) {
			if (stream != null) {
				throw new IllegalStateException(
						"getOutputStream() has already been called for this response");
			}

			final ServletOutputStream outputStream = getOutputStream();
			final String charEnc = getResponse().getCharacterEncoding();
			// HttpServletResponse.getCharacterEncoding() shouldn't return null
			// according the spec, so feel free to remove that "if"
			PrintWriter result;
			if (charEnc == null) {
				result = new PrintWriter(outputStream);
			} else {
				result = new PrintWriter(new OutputStreamWriter(outputStream, charEnc));
			}
			writer = result;
		}
		return writer;
	}

	/** {@inheritDoc} */
	@Override
	public void flushBuffer() throws IOException {
		if (writer != null) {
			writer.flush();
		} else if (stream != null) {
			stream.flush();
		}
	}

	/**
	 * Ferme le flux.
	 * @throws IOException e
	 */
	void close() throws IOException {
		if (writer != null) {
			writer.close();
		} else if (stream != null) {
			stream.close();
		}
	}
}

@@ -3369,16 +3369,272 @@
 %09%09%09%7D%0D%0A%0D%0A
+%09%09%09try %7B%0D%0A%09%09%09%09getOutputStream();%0D%0A%09%09%09%7D catch (final IllegalStateException e) %7B%0D%0A%09%09%09%09// issue 488: if a filter has called getWriter() before the MonitoringFilter, we can't call getOutputStream()%0D%0A%09%09%09%09writer = super.getWriter();%0D%0A%09%09%09%09return writer;%0D%0A%09%09%09%7D%0D%0A%0D%0A
 %09%09%09final

fix issue 488: if a filter has called getWriter() before the MonitoringFilter, we can't call getOutputStream()